Skip to content

perf(gc): keep worker allocations running during another worker's collection - #1213

Merged
frostney merged 2 commits into
mainfrom
claude/sad-napier-a84f51
Aug 25, 2026
Merged

perf(gc): keep worker allocations running during another worker's collection#1213
frostney merged 2 commits into
mainfrom
claude/sad-napier-a84f51

Conversation

@frostney

@frostney frostney commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • One worker's full mark-and-sweep no longer blocks any other worker's per-allocation GC bookkeeping, and workers no longer share a cache line on the allocation path at all. GCCollectLock now guards only global collection coordination (Collect/CollectYoung must still serialize across collectors — the mark epoch GCCurrentMark is process-global); the byte counters a foreign thread can drive (FBytesAllocated, FExternalBytes, FForcedCollectFloor, FPeakBytesAllocated) move to a short-lived per-collector leaf lock, FAccountingLock.
  • RegisterObject/UnregisterObject drop the collect lock entirely: the managed-object list and root sets are owner-thread-confined, because the one cross-thread entry point into a collector is ReleaseExternalBytes through an error object's reserving-collector pointer (TGocciaErrorObjectValue.Destroy). They now hold their own collector's accounting lock for a handful of field updates instead of queueing behind a foreign collection.
  • The fix(runtime): correctness, GC-safety, and conformance fixes across the new stack layers #1212 cross-thread correctness fix is preserved: both sides of the external-byte ledger serialize on the reserving collector's lock; sweeps settle freed bytes in a single locked update inside a finally so Recycle destructors (which may take an accounting lock for a cross-collector release) never run inside an accounting section and a destructor exception cannot strand already-freed bytes; the lock order is strictly collect → accounting (the reservation path drops the accounting lock before it collects); and the per-collector lock lives and dies with its collector on the same lifecycle-invariant terms as the counter fields it guards.
  • Reservation semantics hardened for the split-lock world: both reserve attempts run one atomic fit-test-and-charge (TryChargeExternalBytesLocked), and TryCollectForLimitedBytes grants an already-fitting request without walking the heap — closing a window where a cross-thread release landing after a failed fit test would have turned a grantable request into a spurious guest-visible RangeError (unreachable under the old single-lock design).
  • Non-goal: parallelizing collections themselves — Goccia.gc() on two workers still serializes, as the process-global mark epoch requires.

Deferred performance follow-up from the CodeRabbit review of #1212 (finding on the coarsened GCCollectLock). The second commit applies the results of a fresh-context multi-angle review of the first (two confirmed races fixed, per-collector lock adopted); one pre-existing exposure spotted in that review — unlocked 64-bit BytesAllocated reads that can tear on i386 — predates this PR and is tracked as a follow-up task.

Benchmarks

Contention workload (4 Goccia.gc()-churn files + 12 allocation-churn files, macOS arm64, 10 cores, interleaved A/B runs):

Configuration main this PR Δ
--jobs=8 wall time (median of 5) 22.75 s 10.20 s −55% (distributions do not overlap)
--jobs=1 wall time (median of 3) 41.02 s 39.46 s neutral

(The intermediate global-accounting-lock design measured −19%; moving the lock per-collector, so workers stop bouncing one shared cache line per allocation, roughly tripled the win.) GocciaBenchmarkRunner benchmarks/objects.js single-thread allocation benches: neutral across interleaved runs (deltas flip sign when A/B order is reversed, i.e. ordering noise).

Testing

  • Verified no regressions and confirmed the new feature or bugfix in end-to-end JavaScript/TypeScript tests — full GocciaTestRunner tests green in both modes (12780/12780), on the dev build and on a clean --prod (-O4) build; test-cli, test-cli-apps, and the differential suite green
  • Updated documentation — docs/garbage-collector.md threading model now describes the collect-lock/per-collector-accounting-lock scheme and its ordering rule
  • Optional: Verified no regressions and confirmed the new feature or bugfix in native Pascal tests — new TestCrossThreadReleaseKeepsAccountingExact races a foreign-thread releaser (sized to span the owner-side churn) against registration/collection churn and asserts the byte ledger balances exactly: removing the release-side lock makes it fail 5/5 (mutation-checked with a clean -B rebuild, re-verified against the per-collector lock), and it passes 5/5 under -O4; new TestTryCollectGrantsAlreadyFittingRequestWithoutWalking pins the grant-without-walking contract. Goccia.MemoryLimit.Test, Goccia.Threading.Test, and Goccia.ThreadCleanupLeak.Test green
  • Optional: Verified no benchmark regressions or confirmed benchmark coverage for the change — table above

…lection

Split the GC's synchronization in two: GCCollectLock now guards only global
collection coordination (Collect/CollectYoung, which must serialize across
collectors because the mark epoch is process-global), while a new short-lived
GCAccountingLock guards the byte counters a foreign thread can drive
(FBytesAllocated, FExternalBytes, FForcedCollectFloor, FPeakBytesAllocated).

RegisterObject/UnregisterObject no longer take the collect lock at all — the
managed-object list and root sets are owner-thread-confined, since the one
cross-thread entry point into a collector is ReleaseExternalBytes through an
error object's reserving-collector pointer. A worker's full mark-and-sweep
therefore no longer stalls every other worker's per-allocation bookkeeping:
on a 16-file gc-churn/alloc contention workload at --jobs=8 wall time drops
~19% (22.3s -> 18.0s median of 5 interleaved runs), with single-thread
throughput unchanged (--jobs=1 and BenchmarkRunner objects.js neutral).

The cross-thread correctness fix from #1212 is preserved: both sides of the
external-byte ledger still serialize on one lock, sweeps settle freed bytes
in a single locked update so Recycle destructors (which may take the
accounting lock for a cross-collector release) never run inside an accounting
section, and the lock order collect -> accounting is never reversed — the
reserve path drops the accounting lock before collecting. Both locks stay
unit-global so a late cross-thread release cannot race a per-collector lock's
teardown. A new Pascal test races a foreign-thread releaser against
owner-thread registration/collection churn and asserts the ledger balances to
the byte; removing the release-side lock makes it fail 5/5 (mutation-checked
with a clean -B rebuild).
@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
gocciascript-homepage Ignored Ignored Preview Aug 24, 2026 10:31am

Request Review

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0760d255-f67c-412f-b036-107fa9bd2dea

📥 Commits

Reviewing files that changed from the base of the PR and between 455395b and 8ff983f.

📒 Files selected for processing (3)
  • docs/garbage-collector.md
  • source/units/Goccia.GarbageCollector.Test.pas
  • source/units/Goccia.GarbageCollector.pas

Included review availability: 3 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 4 reviews per hour.


📝 Walkthrough

Walkthrough

The garbage collector now uses a per-collector accounting lock for byte counters and external-memory operations. Collection remains globally serialized. Tests cover fitting reservations and concurrent external-byte releases.

Changes

Garbage collector accounting

Layer / File(s) Summary
Accounting lock contract
source/units/Goccia.GarbageCollector.pas, docs/garbage-collector.md
Defines the accounting lock, initializes it, adds locked accounting helpers, and documents lock ordering and thread ownership.
Counter lifecycle and sweep accounting
source/units/Goccia.GarbageCollector.pas
Moves registration, unregistration, sweep totals, peak resets, and forced-collection floors to synchronized counter updates.
External reservation flow
source/units/Goccia.GarbageCollector.pas
Adds locked fit checks and atomic charges. Reservations retry after collection without holding the accounting lock. Releases use the accounting lock.
Concurrent accounting validation
source/units/Goccia.GarbageCollector.Test.pas
Adds fitting-reservation coverage and worker-thread tests that verify exact byte accounting during allocation and collection activity.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 8ff98

The PR narrows garbage-collection locking so worker allocations can continue during another worker’s collection while preserving accounting and collection coordination; reported tests are green, and no actionable merge-blocking risk remains beyond normal checks.

Sequence Diagram(s)

sequenceDiagram
  participant OwnerThread
  participant TGarbageCollector
  participant CollectionSweep
  participant TCrossThreadReleaser
  OwnerThread->>TGarbageCollector: TryCollectForLimitedBytes
  TGarbageCollector->>TGarbageCollector: Check fit under accounting lock
  TGarbageCollector->>CollectionSweep: Collect when the request does not fit
  CollectionSweep-->>TGarbageCollector: Return after collection
  TGarbageCollector->>TGarbageCollector: Retry the external-byte charge
  TCrossThreadReleaser->>TGarbageCollector: ReleaseExternalBytes
  TGarbageCollector->>TGarbageCollector: Update counters under accounting lock
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: worker allocations continue during another worker's garbage collection.
Description check ✅ Passed The description includes the required summary and testing sections, implementation constraints, non-goals, documentation updates, and test results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (3 skipped: 3 unsupported.)
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Web Tooling Benchmark

Workload Status Goccia
acorn pass 0.03 runs/s
babel pass 0.01 runs/s
babel-minify pass 0.10 runs/s
babylon pass 0.04 runs/s
buble pass 0.08 runs/s
chai pass 0.08 runs/s
coffeescript pass 0.01 runs/s
espree pass 0.03 runs/s
esprima pass 0.05 runs/s
jshint pass 0.01 runs/s
lebab pass 0.07 runs/s
postcss pass 0.02 runs/s
prepack pass 0.11 runs/s
prettier pass 0.09 runs/s
source-map pass 0.03 runs/s
terser pass 0.18 runs/s
typescript pass 0.11 runs/s
uglify-js pass 0.06 runs/s

18 pinned Web Tooling workloads; 18 workloads produced at least one Goccia sample. Raw results from 1 sample per workload; full stdout/stderr for failures and min/max/CV stay in the web-tooling-report artifact. This lane is Goccia-only by design.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Suite Timing

Test Runner (interpreted: 12,780 passed; bytecode: 12,780 passed)
Metric Interpreted Bytecode
Total 12780 12780
Passed 12780 ✅ 12780 ✅
Workers 4 4
Test Duration 15.74s 15.63s
Lex (cumulative) 1.55s 1.58s
Parse (cumulative) 786.8ms 798.0ms
Compile (cumulative) 1.08s
Execute (cumulative) 557.6ms 16.17s
Engine Total (cumulative) 2.89s 19.63s
Lex (avg/worker) 387.2ms 396.1ms
Parse (avg/worker) 196.7ms 199.5ms
Compile (avg/worker) 269.1ms
Execute (avg/worker) 139.4ms 4.04s
Engine Total (avg/worker) 723.3ms 4.91s

Memory

GC rows aggregate the main thread plus all worker thread-local GCs. Test runner worker shutdown frees thread-local heaps in bulk; that shutdown reclamation is not counted as GC collections or collected objects.

Metric Interpreted Bytecode
GC Live 77.01 MiB 53.81 MiB
GC Peak Live 209.90 MiB 166.63 MiB
GC Allocated During Run 700.48 MiB 611.57 MiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 1,004 1,010
GC Collected Objects 5,314,430 4,769,124
Heap Start Allocated 371.1 KiB 371.1 KiB
Heap End Allocated 3.00 MiB 2.99 MiB
Heap Delta Allocated 2.64 MiB 2.63 MiB
Heap Delta Free 2.20 MiB 2.21 MiB
Benchmarks (interpreted: 440; bytecode: 440)
Metric Interpreted Bytecode
Total 440 440
Workers 4 4
Duration 3.09min 2.85min

Memory

GC rows aggregate the main thread plus all worker thread-local GCs. Benchmark runner performs explicit between-file collections, so collection and collected-object counts can be much higher than the test runner.

Metric Interpreted Bytecode
GC Live 85.0 KiB 85.0 KiB
GC Peak Live 480.54 MiB 287.53 MiB
GC Allocated During Run 20.88 GiB 12.23 GiB
GC Limit 7.81 GiB 7.81 GiB
GC Collections 8,520 5,574
GC Collected Objects 224,490,290 167,488,756
Heap Start Allocated 1.37 MiB 1.37 MiB
Heap End Allocated 1.37 MiB 1.37 MiB
Heap Delta Allocated 3.2 KiB 3.2 KiB
Boot
Metric Interpreted Bytecode
Boot (median) 7.6ms 7.6ms
Boot (min) 7.5ms 7.5ms

Empty-script (0;) end-to-end process wall-clock for GocciaScriptLoader, min and median over 60 runs after 10 warmups. Includes a fixed process / dynamic-loader floor that does not shrink, so it understates the engine-boot speedup; treat as practical boot time, not pure engine work.

Measured on ubuntu-latest x64.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

440 benchmarks · PR vs same-runner main build

Interpreted: 🟢 426 improved · 🔴 7 regressed · 7 unchanged · avg +46.7%
Bytecode: 🟢 403 improved · 🔴 9 regressed · 28 unchanged · avg +43.3%

Typical per-run noise (median variance): interpreted ±1.7%, bytecode ±1.6%. Deltas within noise overlap and read as unchanged.

arraybuffer.js — Interp: 🟢 14 · avg +48.3% · Bytecode: 🟢 12, 🔴 1, 1 unch. · avg +33.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
create ArrayBuffer(0) 56,242 ops/sec [46,293..58,241] → 87,854 ops/sec [85,318..92,152] 🟢 +56.2% 82,984 ops/sec [76,400..86,135] → 122,778 ops/sec [121,946..123,454] 🟢 +48.0%
create ArrayBuffer(64) 48,740 ops/sec [48,454..50,114] → 84,687 ops/sec [82,108..88,110] 🟢 +73.8% 67,741 ops/sec [67,178..78,576] → 117,218 ops/sec [113,584..121,409] 🟢 +73.0%
create ArrayBuffer(1024) 54,656 ops/sec [53,213..56,660] → 79,557 ops/sec [66,779..102,882] 🟢 +45.6% 72,856 ops/sec [60,390..84,316] → 107,488 ops/sec [106,123..110,150] 🟢 +47.5%
create ArrayBuffer(8192) 44,022 ops/sec [36,327..48,481] → 59,563 ops/sec [59,159..68,151] 🟢 +35.3% 48,853 ops/sec [44,776..53,146] → 69,605 ops/sec [68,146..73,988] 🟢 +42.5%
slice full buffer (64 bytes) 48,814 ops/sec [41,242..50,238] → 69,566 ops/sec [69,313..69,847] 🟢 +42.5% 55,649 ops/sec [41,972..67,537] → 76,158 ops/sec [75,971..76,590] 🟢 +36.9%
slice half buffer (512 of 1024 bytes) 48,010 ops/sec [41,450..52,602] → 65,640 ops/sec [65,156..69,935] 🟢 +36.7% 61,912 ops/sec [48,219..64,868] → 71,681 ops/sec [70,540..73,004] 🟢 +15.8%
slice with negative indices 40,358 ops/sec [35,152..46,817] → 60,731 ops/sec [60,212..61,138] 🟢 +50.5% 52,823 ops/sec [35,360..61,051] → 71,815 ops/sec [71,624..76,213] 🟢 +36.0%
slice empty range 49,498 ops/sec [43,236..57,704] → 66,695 ops/sec [64,705..67,209] 🟢 +34.7% 59,756 ops/sec [58,539..67,342] → 71,737 ops/sec [70,997..72,365] 🟢 +20.1%
byteLength access 117,089 ops/sec [115,364..131,056] → 194,150 ops/sec [184,498..195,123] 🟢 +65.8% 154,363 ops/sec [137,884..181,101] → 221,422 ops/sec [216,444..222,917] 🟢 +43.4%
Symbol.toStringTag access 127,045 ops/sec [113,278..145,319] → 184,411 ops/sec [181,793..185,724] 🟢 +45.2% 246,732 ops/sec [237,371..313,690] → 224,478 ops/sec [213,386..259,989] ~ overlap (-9.0%)
ArrayBuffer.isView 102,155 ops/sec [89,645..135,495] → 150,514 ops/sec [139,213..159,053] 🟢 +47.3% 186,443 ops/sec [177,301..202,298] → 169,399 ops/sec [168,745..169,701] 🔴 -9.1%
clone ArrayBuffer(64) 72,457 ops/sec [67,575..79,336] → 107,161 ops/sec [105,126..112,961] 🟢 +47.9% 79,283 ops/sec [68,817..119,742] → 123,915 ops/sec [122,894..137,824] 🟢 +56.3%
clone ArrayBuffer(1024) 68,807 ops/sec [63,414..80,778] → 100,275 ops/sec [97,906..100,387] 🟢 +45.7% 89,154 ops/sec [59,264..107,176] → 113,228 ops/sec [111,406..114,486] 🟢 +27.0%
clone ArrayBuffer inside object 45,146 ops/sec [40,673..49,005] → 67,094 ops/sec [65,419..69,904] 🟢 +48.6% 53,221 ops/sec [42,702..66,034] → 73,247 ops/sec [72,142..73,835] 🟢 +37.6%
arrays.js — Interp: 🟢 18, 1 unch. · avg +50.9% · Bytecode: 🟢 19 · avg +41.9%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
Array.from length 100 1,408 ops/sec [1,129..1,571] → 2,322 ops/sec [2,304..2,335] 🟢 +64.9% 1,233 ops/sec [1,126..1,276] → 1,981 ops/sec [1,943..2,245] 🟢 +60.6%
Array.from 10 elements 8,729 ops/sec [7,744..10,359] → 14,031 ops/sec [13,208..14,114] 🟢 +60.7% 8,892 ops/sec [8,858..8,912] → 14,247 ops/sec [13,971..15,022] 🟢 +60.2%
Array.of 10 elements 29,294 ops/sec [24,038..34,152] → 42,946 ops/sec [42,383..44,202] 🟢 +46.6% 33,779 ops/sec [25,810..38,957] → 47,887 ops/sec [47,621..48,079] 🟢 +41.8%
spread into new array 47,808 ops/sec [42,651..54,212] → 68,558 ops/sec [51,618..68,746] ~ overlap (+43.4%) 29,174 ops/sec [26,394..31,366] → 41,631 ops/sec [41,314..57,223] 🟢 +42.7%
map over 50 elements 2,577 ops/sec [2,537..2,599] → 3,911 ops/sec [3,869..3,958] 🟢 +51.8% 3,314 ops/sec [2,557..3,666] → 4,104 ops/sec [4,058..4,117] 🟢 +23.8%
filter over 50 elements 2,829 ops/sec [2,368..3,180] → 4,034 ops/sec [4,012..4,075] 🟢 +42.6% 3,017 ops/sec [2,886..3,802] → 4,469 ops/sec [4,367..4,492] 🟢 +48.1%
reduce sum 50 elements 3,238 ops/sec [2,828..3,904] → 5,312 ops/sec [4,893..5,806] 🟢 +64.0% 3,743 ops/sec [2,208..4,109] → 4,902 ops/sec [4,877..4,925] 🟢 +31.0%
forEach over 50 elements 2,567 ops/sec [2,041..2,954] → 3,476 ops/sec [3,463..3,498] 🟢 +35.4% 3,914 ops/sec [3,866..3,973] → 5,226 ops/sec [5,109..5,292] 🟢 +33.5%
find in 50 elements 4,199 ops/sec [3,457..4,297] → 6,646 ops/sec [6,620..6,745] 🟢 +58.3% 4,128 ops/sec [3,729..5,829] → 6,470 ops/sec [6,408..6,495] 🟢 +56.7%
sort 20 elements 2,446 ops/sec [2,399..2,527] → 3,596 ops/sec [3,581..3,713] 🟢 +47.0% 2,858 ops/sec [2,385..3,032] → 3,794 ops/sec [3,759..3,802] 🟢 +32.7%
flat nested array 19,278 ops/sec [16,998..20,673] → 25,362 ops/sec [25,018..27,254] 🟢 +31.6% 20,093 ops/sec [16,034..24,370] → 27,975 ops/sec [27,442..28,270] 🟢 +39.2%
flatMap 10,402 ops/sec [9,523..12,288] → 15,579 ops/sec [15,204..15,615] 🟢 +49.8% 11,686 ops/sec [10,690..13,862] → 16,731 ops/sec [16,587..17,015] 🟢 +43.2%
map inside map (5x5) 3,067 ops/sec [2,618..3,445] → 4,583 ops/sec [4,559..5,384] 🟢 +49.4% 3,403 ops/sec [2,768..3,992] → 4,608 ops/sec [4,601..4,645] 🟢 +35.4%
filter inside map (5x10) 2,083 ops/sec [2,016..2,298] → 3,064 ops/sec [3,039..3,075] 🟢 +47.0% 2,326 ops/sec [1,991..2,703] → 3,231 ops/sec [3,102..3,500] 🟢 +38.9%
reduce inside map (5x10) 2,437 ops/sec [2,374..2,739] → 4,151 ops/sec [3,823..4,288] 🟢 +70.3% 2,535 ops/sec [2,147..3,068] → 3,746 ops/sec [3,720..3,811] 🟢 +47.8%
forEach inside forEach (5x10) 2,009 ops/sec [1,614..2,084] → 2,874 ops/sec [2,862..2,896] 🟢 +43.1% 2,736 ops/sec [2,361..2,951] → 4,118 ops/sec [4,003..4,455] 🟢 +50.5%
find inside some (10x10) 1,884 ops/sec [1,283..2,343] → 2,960 ops/sec [2,904..3,124] 🟢 +57.1% 2,003 ops/sec [1,899..2,733] → 2,819 ops/sec [2,804..2,931] 🟢 +40.8%
map+filter chain nested (5x20) 546 ops/sec [462..757] → 910 ops/sec [898..913] 🟢 +66.8% 676 ops/sec [557..681] → 940 ops/sec [935..942] 🟢 +39.0%
reduce flatten (10x5) 4,492 ops/sec [3,106..5,857] → 6,191 ops/sec [6,075..7,278] 🟢 +37.8% 2,153 ops/sec [1,759..2,170] → 2,813 ops/sec [2,714..4,467] 🟢 +30.7%
async-await.js — Interp: 🟢 6 · avg +49.9% · Bytecode: 🟢 5, 1 unch. · avg +43.2%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
single await 12,618 ops/sec [9,885..15,570] → 19,960 ops/sec [19,902..20,109] 🟢 +58.2% 14,816 ops/sec [11,433..18,067] → 22,370 ops/sec [22,151..22,606] 🟢 +51.0%
multiple awaits 5,052 ops/sec [4,389..6,941] → 8,644 ops/sec [7,748..9,783] 🟢 +71.1% 5,003 ops/sec [4,959..6,907] → 8,086 ops/sec [8,012..8,110] 🟢 +61.6%
await non-Promise value 17,867 ops/sec [15,754..20,320] → 28,626 ops/sec [27,011..28,807] 🟢 +60.2% 21,653 ops/sec [13,680..28,847] → 33,049 ops/sec [31,951..33,663] 🟢 +52.6%
await with try/catch 12,875 ops/sec [11,734..13,784] → 17,684 ops/sec [17,516..18,283] 🟢 +37.3% 14,963 ops/sec [13,637..16,748] → 21,979 ops/sec [21,690..25,613] 🟢 +46.9%
await Promise.all 3,476 ops/sec [3,158..4,054] → 4,735 ops/sec [4,696..4,762] 🟢 +36.2% 3,517 ops/sec [2,704..3,837] → 4,774 ops/sec [4,763..4,780] 🟢 +35.7%
nested async function call 8,457 ops/sec [8,166..8,857] → 11,546 ops/sec [10,672..11,733] 🟢 +36.5% 10,032 ops/sec [7,851..10,826] → 11,143 ops/sec [10,447..11,508] ~ overlap (+11.1%)
async-generators.js — Interp: 🟢 2 · avg +53.3% · Bytecode: 🟢 1, 1 unch. · avg +51.5%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
for-await-of over async generator 905 ops/sec [834..937] → 1,289 ops/sec [1,193..1,323] 🟢 +42.4% 377 ops/sec [294..526] → 547 ops/sec [516..551] ~ overlap (+44.9%)
async generator with await in body 3,200 ops/sec [3,128..3,306] → 5,253 ops/sec [5,102..6,593] 🟢 +64.1% 2,703 ops/sec [2,337..2,725] → 4,272 ops/sec [4,171..4,311] 🟢 +58.0%
atomics.js — Interp: 🟢 6 · avg +47.3% · Bytecode: 🟢 6 · avg +40.0%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
load and store Int32Array 47,303 ops/sec [39,468..56,479] → 72,169 ops/sec [63,735..72,788] 🟢 +52.6% 62,475 ops/sec [58,912..65,645] → 91,531 ops/sec [89,611..91,755] 🟢 +46.5%
read-modify-write Int32Array 34,285 ops/sec [30,187..43,800] → 53,457 ops/sec [52,928..53,565] 🟢 +55.9% 43,041 ops/sec [39,218..43,867] → 62,476 ops/sec [58,217..67,322] 🟢 +45.2%
compareExchange hit and miss 32,730 ops/sec [29,847..32,980] → 49,971 ops/sec [49,419..53,703] 🟢 +52.7% 41,081 ops/sec [32,341..46,553] → 58,470 ops/sec [58,238..61,150] 🟢 +42.3%
wait with zero timeout 81,208 ops/sec [68,043..84,344] → 115,225 ops/sec [114,753..115,517] 🟢 +41.9% 101,697 ops/sec [98,300..129,375] → 152,813 ops/sec [151,376..154,287] 🟢 +50.3%
waitAsync synchronous not-equal 57,983 ops/sec [51,081..63,849] → 82,793 ops/sec [80,766..84,278] 🟢 +42.8% 78,704 ops/sec [75,413..85,761] → 99,400 ops/sec [97,994..106,966] 🟢 +26.3%
notify with no waiters 85,472 ops/sec [80,893..97,364] → 117,696 ops/sec [117,278..118,064] 🟢 +37.7% 120,613 ops/sec [114,742..120,956] → 156,457 ops/sec [152,563..170,346] 🟢 +29.7%
base64.js — Interp: 🟢 10 · avg +47.9% · Bytecode: 🟢 10 · avg +37.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
short ASCII (13 chars) 1,420 ops/sec [1,212..1,584] → 1,969 ops/sec [1,961..2,061] 🟢 +38.7% 1,669 ops/sec [1,513..1,686] → 1,912 ops/sec [1,906..1,926] 🟢 +14.6%
medium ASCII (450 chars) 54 ops/sec [50..59] → 72 ops/sec [71..87] 🟢 +32.8% 56 ops/sec [51..57] → 70 ops/sec [70..71] 🟢 +25.2%
Latin-1 characters 1,869 ops/sec [1,842..2,249] → 2,852 ops/sec [2,825..2,872] 🟢 +52.5% 2,044 ops/sec [1,860..2,249] → 2,749 ops/sec [2,722..2,776] 🟢 +34.5%
short base64 (20 chars) 991 ops/sec [913..1,033] → 1,463 ops/sec [1,454..1,466] 🟢 +47.6% 975 ops/sec [900..1,086] → 1,432 ops/sec [1,415..1,440] 🟢 +46.9%
medium base64 (600 chars) 40 ops/sec [35..43] → 57 ops/sec [57..63] 🟢 +44.2% 40 ops/sec [36..40] → 55 ops/sec [54..55] 🟢 +38.8%
Latin-1 output 1,341 ops/sec [1,314..1,351] → 2,031 ops/sec [2,020..2,063] 🟢 +51.5% 1,478 ops/sec [1,270..1,618] → 2,024 ops/sec [1,938..2,144] 🟢 +37.0%
forgiving (no padding) 1,988 ops/sec [1,765..2,148] → 3,016 ops/sec [2,990..3,070] 🟢 +51.8% 2,084 ops/sec [1,917..2,406] → 2,901 ops/sec [2,845..2,954] 🟢 +39.2%
with whitespace 923 ops/sec [833..996] → 1,419 ops/sec [1,397..1,436] 🟢 +53.7% 1,050 ops/sec [992..1,174] → 1,358 ops/sec [1,337..1,445] 🟢 +29.3%
atob(btoa(short)) 561 ops/sec [502..660] → 831 ops/sec [824..843] 🟢 +48.3% 579 ops/sec [537..650] → 881 ops/sec [807..959] 🟢 +52.1%
atob(btoa(medium)) 20 ops/sec [19..21] → 32 ops/sec [31..35] 🟢 +58.2% 20 ops/sec [20..21] → 31 ops/sec [31..32] 🟢 +55.8%
classes.js — Interp: 🟢 31 · avg +37.3% · Bytecode: 🟢 31 · avg +37.7%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
simple class new 22,325 ops/sec [21,328..22,465] → 31,320 ops/sec [30,279..35,701] 🟢 +40.3% 38,477 ops/sec [37,449..45,058] → 48,262 ops/sec [47,942..48,580] 🟢 +25.4%
class with defaults 18,500 ops/sec [18,405..18,603] → 24,591 ops/sec [24,374..24,750] 🟢 +32.9% 27,375 ops/sec [23,339..31,629] → 35,375 ops/sec [34,988..37,789] 🟢 +29.2%
50 instances via Array.from 809 ops/sec [720..971] → 1,072 ops/sec [1,062..1,098] 🟢 +32.6% 926 ops/sec [757..1,236] → 1,332 ops/sec [1,330..1,335] 🟢 +43.8%
instance method call 11,607 ops/sec [10,171..12,539] → 15,310 ops/sec [15,195..17,046] 🟢 +31.9% 19,439 ops/sec [18,524..19,883] → 25,763 ops/sec [25,647..25,861] 🟢 +32.5%
static method call 17,701 ops/sec [16,139..22,196] → 26,199 ops/sec [25,658..32,166] 🟢 +48.0% 44,195 ops/sec [35,885..49,462] → 53,547 ops/sec [53,032..53,803] 🟢 +21.2%
single-level inheritance 9,061 ops/sec [8,101..9,906] → 12,655 ops/sec [12,361..14,388] 🟢 +39.7% 13,612 ops/sec [12,347..14,798] → 17,381 ops/sec [16,917..18,933] 🟢 +27.7%
two-level inheritance 8,114 ops/sec [7,493..8,841] → 10,993 ops/sec [10,918..11,028] 🟢 +35.5% 11,537 ops/sec [10,660..11,581] → 14,349 ops/sec [13,945..15,567] 🟢 +24.4%
private field access 11,430 ops/sec [10,398..12,417] → 16,092 ops/sec [16,027..16,210] 🟢 +40.8% 9,136 ops/sec [7,978..10,138] → 11,777 ops/sec [11,661..16,628] 🟢 +28.9%
private methods 12,579 ops/sec [10,312..14,458] → 17,372 ops/sec [17,071..21,136] 🟢 +38.1% 9,381 ops/sec [7,544..9,783] → 12,283 ops/sec [12,248..12,310] 🟢 +30.9%
getter/setter access 12,360 ops/sec [9,755..13,620] → 17,221 ops/sec [16,984..17,395] 🟢 +39.3% 20,064 ops/sec [16,368..20,357] → 26,527 ops/sec [26,447..26,913] 🟢 +32.2%
class decorator (identity) 19,278 ops/sec [16,088..21,367] → 25,471 ops/sec [25,375..25,783] 🟢 +32.1% 24,401 ops/sec [16,579..26,730] → 28,548 ops/sec [27,821..32,035] 🟢 +17.0%
class decorator (wrapping) 10,683 ops/sec [9,612..11,324] → 14,568 ops/sec [14,451..15,192] 🟢 +36.4% 12,821 ops/sec [9,418..14,079] → 15,736 ops/sec [15,476..15,922] 🟢 +22.7%
identity method decorator 13,271 ops/sec [11,979..14,648] → 19,433 ops/sec [18,756..22,828] 🟢 +46.4% 20,319 ops/sec [18,613..20,995] → 24,462 ops/sec [24,170..25,046] 🟢 +20.4%
wrapping method decorator 10,659 ops/sec [9,581..11,255] → 15,368 ops/sec [14,967..21,379] 🟢 +44.2% 12,372 ops/sec [11,027..12,608] → 18,285 ops/sec [17,360..20,130] 🟢 +47.8%
stacked method decorators (x3) 7,488 ops/sec [6,404..8,253] → 12,425 ops/sec [10,897..14,704] 🟢 +65.9% 7,987 ops/sec [7,650..8,763] → 13,026 ops/sec [12,799..13,345] 🟢 +63.1%
identity field decorator 13,465 ops/sec [10,219..16,216] → 21,533 ops/sec [21,198..22,710] 🟢 +59.9% 15,767 ops/sec [13,803..18,567] → 22,647 ops/sec [22,587..22,842] 🟢 +43.6%
field initializer decorator 11,930 ops/sec [9,763..14,037] → 18,240 ops/sec [17,995..18,323] 🟢 +52.9% 13,274 ops/sec [12,208..16,516] → 20,065 ops/sec [19,763..20,554] 🟢 +51.2%
getter decorator (identity) 13,411 ops/sec [12,718..14,239] → 16,752 ops/sec [16,668..16,949] 🟢 +24.9% 9,574 ops/sec [7,663..10,512] → 14,699 ops/sec [14,532..14,811] 🟢 +53.5%
setter decorator (identity) 11,181 ops/sec [10,707..12,039] → 13,817 ops/sec [13,746..13,835] 🟢 +23.6% 8,205 ops/sec [6,944..9,707] → 11,907 ops/sec [11,850..11,976] 🟢 +45.1%
static method decorator 17,003 ops/sec [15,345..17,344] → 20,863 ops/sec [20,618..25,238] 🟢 +22.7% 23,181 ops/sec [19,429..26,522] → 27,634 ops/sec [27,295..31,394] 🟢 +19.2%
static field decorator 18,796 ops/sec [17,734..20,808] → 24,308 ops/sec [24,245..26,485] 🟢 +29.3% 23,759 ops/sec [17,313..24,982] → 29,967 ops/sec [28,598..30,643] 🟢 +26.1%
private method decorator 9,061 ops/sec [8,388..10,642] → 14,782 ops/sec [14,570..18,273] 🟢 +63.1% 13,470 ops/sec [9,914..16,547] → 16,780 ops/sec [16,623..17,336] 🟢 +24.6%
private field decorator 11,563 ops/sec [10,849..12,708] → 15,849 ops/sec [15,700..15,925] 🟢 +37.1% 12,364 ops/sec [11,991..12,619] → 15,326 ops/sec [15,149..15,705] 🟢 +24.0%
plain auto-accessor (no decorator) 20,014 ops/sec [17,267..21,948] → 25,942 ops/sec [25,650..26,237] 🟢 +29.6% 23,522 ops/sec [20,332..29,384] → 31,312 ops/sec [31,209..31,686] 🟢 +33.1%
auto-accessor with decorator 12,419 ops/sec [12,146..14,322] → 16,659 ops/sec [16,252..16,705] 🟢 +34.1% 12,618 ops/sec [11,790..14,057] → 17,578 ops/sec [17,030..21,680] 🟢 +39.3%
decorator writing metadata 10,092 ops/sec [9,306..11,464] → 14,108 ops/sec [13,611..14,399] 🟢 +39.8% 11,643 ops/sec [9,675..14,665] → 18,108 ops/sec [17,709..19,004] 🟢 +55.5%
static getter read 22,027 ops/sec [20,184..24,066] → 29,556 ops/sec [29,479..29,611] 🟢 +34.2% 32,669 ops/sec [27,425..41,707] → 54,601 ops/sec [48,573..58,114] 🟢 +67.1%
static getter/setter pair 16,466 ops/sec [14,840..18,880] → 22,227 ops/sec [22,165..22,360] 🟢 +35.0% 24,016 ops/sec [19,862..25,157] → 35,976 ops/sec [35,617..36,898] 🟢 +49.8%
inherited static getter 14,992 ops/sec [13,210..16,412] → 18,200 ops/sec [18,090..18,803] 🟢 +21.4% 19,592 ops/sec [17,842..26,332] → 31,177 ops/sec [30,885..33,301] 🟢 +59.1%
inherited static setter 17,609 ops/sec [16,675..19,669] → 20,530 ops/sec [20,283..20,635] 🟢 +16.6% 19,105 ops/sec [18,806..23,034] → 30,073 ops/sec [29,357..32,343] 🟢 +57.4%
inherited static getter with this binding 11,913 ops/sec [10,474..12,655] → 15,332 ops/sec [15,200..15,753] 🟢 +28.7% 16,472 ops/sec [15,398..16,624] → 24,894 ops/sec [23,873..28,135] 🟢 +51.1%
closures.js — Interp: 🟢 11 · avg +58.4% · Bytecode: 🟢 11 · avg +47.7%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
closure over single variable 17,317 ops/sec [16,066..20,399] → 26,632 ops/sec [24,756..27,785] 🟢 +53.8% 66,194 ops/sec [64,472..67,066] → 93,136 ops/sec [91,953..101,867] 🟢 +40.7%
closure over multiple variables 19,904 ops/sec [17,942..21,563] → 29,733 ops/sec [29,569..32,043] 🟢 +49.4% 75,315 ops/sec [71,243..75,715] → 95,189 ops/sec [94,159..95,549] 🟢 +26.4%
nested closures 22,981 ops/sec [18,160..26,508] → 33,526 ops/sec [33,273..47,886] 🟢 +45.9% 67,835 ops/sec [54,229..76,914] → 87,198 ops/sec [85,324..90,082] 🟢 +28.5%
function as argument 16,129 ops/sec [13,224..16,904] → 23,288 ops/sec [23,120..23,885] 🟢 +44.4% 63,938 ops/sec [49,729..66,122] → 84,982 ops/sec [84,835..91,932] 🟢 +32.9%
function returning function 21,026 ops/sec [20,477..21,517] → 31,950 ops/sec [29,232..32,682] 🟢 +52.0% 69,448 ops/sec [55,044..73,825] → 96,708 ops/sec [95,378..113,832] 🟢 +39.3%
compose two functions 12,650 ops/sec [9,231..14,579] → 19,022 ops/sec [18,691..19,188] 🟢 +50.4% 43,434 ops/sec [33,412..53,150] → 58,573 ops/sec [58,130..58,939] 🟢 +34.9%
fn.call 22,100 ops/sec [20,335..26,191] → 38,705 ops/sec [36,015..40,580] 🟢 +75.1% 57,222 ops/sec [55,101..77,061] → 89,950 ops/sec [85,942..113,369] 🟢 +57.2%
fn.apply 20,998 ops/sec [20,774..21,444] → 35,847 ops/sec [32,283..45,277] 🟢 +70.7% 45,064 ops/sec [39,217..55,764] → 71,582 ops/sec [68,880..72,334] 🟢 +58.8%
fn.bind 20,927 ops/sec [19,820..22,771] → 33,658 ops/sec [33,548..33,936] 🟢 +60.8% 50,311 ops/sec [45,046..53,422] → 86,198 ops/sec [85,418..93,491] 🟢 +71.3%
recursive sum to 50 1,688 ops/sec [1,482..1,978] → 3,050 ops/sec [3,035..3,094] 🟢 +80.7% 28,607 ops/sec [24,376..36,844] → 48,566 ops/sec [47,958..48,982] 🟢 +69.8%
recursive tree traversal 3,063 ops/sec [2,649..3,451] → 4,883 ops/sec [4,852..4,957] 🟢 +59.4% 8,118 ops/sec [6,641..10,984] → 13,406 ops/sec [13,277..13,472] 🟢 +65.1%
collections.js — Interp: 🟢 12 · avg +51.7% · Bytecode: 🟢 10, 🔴 2 · avg +48.9%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
add 50 elements 1,709 ops/sec [1,441..2,128] → 2,577 ops/sec [2,563..2,641] 🟢 +50.8% 1,718 ops/sec [1,383..1,967] → 2,801 ops/sec [2,712..2,818] 🟢 +63.0%
has lookup (50 elements) 30,962 ops/sec [26,138..38,656] → 47,250 ops/sec [46,157..48,536] 🟢 +52.6% 42,398 ops/sec [27,696..42,558] → 64,052 ops/sec [62,451..66,548] 🟢 +51.1%
delete elements 8,445 ops/sec [7,566..9,369] → 12,673 ops/sec [12,529..12,713] 🟢 +50.1% 9,886 ops/sec [5,973..11,374] → 14,396 ops/sec [13,937..15,135] 🟢 +45.6%
forEach iteration 2,197 ops/sec [2,008..2,734] → 3,743 ops/sec [3,576..4,192] 🟢 +70.4% 3,947 ops/sec [2,960..4,171] → 6,107 ops/sec [5,665..8,086] 🟢 +54.7%
spread to array 7,089 ops/sec [6,041..8,205] → 12,751 ops/sec [10,254..13,990] 🟢 +79.9% 30,283 ops/sec [28,660..38,319] → 49,081 ops/sec [48,550..52,773] 🟢 +62.1%
deduplicate array 6,411 ops/sec [5,030..7,245] → 9,422 ops/sec [9,329..11,434] 🟢 +47.0% 8,294 ops/sec [7,155..10,766] → 14,028 ops/sec [13,909..15,035] 🟢 +69.1%
set 50 entries 1,228 ops/sec [874..1,431] → 1,916 ops/sec [1,901..1,929] 🟢 +56.1% 1,244 ops/sec [1,109..1,621] → 2,268 ops/sec [2,211..2,436] 🟢 +82.3%
get lookup (50 entries) 32,887 ops/sec [30,018..39,170] → 44,391 ops/sec [43,850..52,422] 🟢 +35.0% 78,058 ops/sec [74,174..82,320] → 70,160 ops/sec [66,643..70,369] 🔴 -10.1%
has check 41,573 ops/sec [36,505..53,066] → 57,760 ops/sec [57,287..58,187] 🟢 +38.9% 98,920 ops/sec [90,553..110,964] → 88,143 ops/sec [87,764..89,389] 🔴 -10.9%
delete entries 8,416 ops/sec [8,360..8,657] → 11,345 ops/sec [11,273..11,528] 🟢 +34.8% 8,281 ops/sec [7,676..11,135] → 13,608 ops/sec [13,365..14,684] 🟢 +64.3%
forEach iteration 2,509 ops/sec [2,201..3,161] → 3,722 ops/sec [3,633..3,828] 🟢 +48.4% 3,547 ops/sec [3,359..3,928] → 6,146 ops/sec [5,703..6,546] 🟢 +73.3%
keys/values/entries 1,932 ops/sec [1,749..1,948] → 3,028 ops/sec [2,995..3,192] 🟢 +56.8% 6,408 ops/sec [4,624..7,408] → 9,112 ops/sec [8,447..11,116] 🟢 +42.2%
csv.js — Interp: 🟢 13 · avg +59.2% · Bytecode: 🟢 13 · avg +56.6%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
parse simple 3-column CSV 21,613 ops/sec [20,262..21,832] → 34,119 ops/sec [34,109..34,128] 🟢 +57.9% 22,843 ops/sec [20,306..28,013] → 37,179 ops/sec [36,069..37,298] 🟢 +62.8%
parse 10-row CSV 6,170 ops/sec [5,913..6,189] → 9,883 ops/sec [9,477..10,479] 🟢 +60.2% 5,766 ops/sec [5,174..6,146] → 10,098 ops/sec [9,787..10,859] 🟢 +75.2%
parse 100-row CSV 888 ops/sec [755..995] → 1,524 ops/sec [1,404..2,493] 🟢 +71.6% 990 ops/sec [816..1,051] → 1,564 ops/sec [1,551..1,644] 🟢 +58.1%
parse CSV with quoted fields 31,426 ops/sec [27,325..36,259] → 55,469 ops/sec [52,732..59,681] 🟢 +76.5% 39,955 ops/sec [28,497..49,397] → 58,479 ops/sec [58,148..72,368] 🟢 +46.4%
parse without headers (array of arrays) 2,464 ops/sec [1,913..2,891] → 4,399 ops/sec [4,276..5,004] 🟢 +78.5% 2,869 ops/sec [2,143..3,172] → 4,463 ops/sec [4,386..4,820] 🟢 +55.6%
parse with semicolon delimiter 4,413 ops/sec [3,945..4,985] → 7,184 ops/sec [7,071..10,086] 🟢 +62.8% 4,452 ops/sec [4,026..5,584] → 7,564 ops/sec [7,480..10,325] 🟢 +69.9%
stringify array of objects 27,652 ops/sec [23,593..28,124] → 37,928 ops/sec [37,766..38,020] 🟢 +37.2% 31,280 ops/sec [27,660..41,524] → 49,824 ops/sec [49,278..54,453] 🟢 +59.3%
stringify array of arrays 11,384 ops/sec [11,206..11,505] → 16,106 ops/sec [15,831..16,482] 🟢 +41.5% 11,836 ops/sec [9,716..12,303] → 17,994 ops/sec [17,921..18,106] 🟢 +52.0%
stringify with values needing escaping 15,885 ops/sec [14,776..19,175] → 21,423 ops/sec [21,054..22,098] 🟢 +34.9% 16,483 ops/sec [13,883..17,694] → 25,046 ops/sec [24,854..26,136] 🟢 +52.0%
reviver converts numbers 339 ops/sec [337..343] → 502 ops/sec [492..512] 🟢 +48.0% 395 ops/sec [357..482] → 563 ops/sec [556..576] 🟢 +42.6%
reviver filters empty to null 3,659 ops/sec [3,611..4,356] → 7,150 ops/sec [6,517..7,433] 🟢 +95.4% 6,069 ops/sec [5,162..6,777] → 8,771 ops/sec [8,711..8,978] 🟢 +44.5%
parse then stringify 3,744 ops/sec [2,904..4,350] → 5,866 ops/sec [5,817..6,037] 🟢 +56.7% 4,168 ops/sec [3,592..5,251] → 6,078 ops/sec [6,015..6,110] 🟢 +45.8%
stringify then parse 3,899 ops/sec [3,342..4,237] → 5,802 ops/sec [5,715..6,703] 🟢 +48.8% 3,823 ops/sec [3,346..5,290] → 6,544 ops/sec [6,123..9,077] 🟢 +71.2%
destructuring.js — Interp: 🟢 22 · avg +42.5% · Bytecode: 🟢 22 · avg +49.6%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
simple array destructuring 37,338 ops/sec [32,083..45,213] → 50,352 ops/sec [49,892..50,871] 🟢 +34.9% 40,718 ops/sec [32,733..49,724] → 71,269 ops/sec [70,999..71,339] 🟢 +75.0%
with rest element 31,475 ops/sec [28,560..32,485] → 41,795 ops/sec [40,910..50,719] 🟢 +32.8% 33,281 ops/sec [27,906..40,372] → 54,918 ops/sec [54,557..55,629] 🟢 +65.0%
with defaults 38,873 ops/sec [34,141..44,046] → 52,023 ops/sec [51,649..69,191] 🟢 +33.8% 57,712 ops/sec [42,261..73,933] → 76,847 ops/sec [75,695..77,525] 🟢 +33.2%
skip elements 39,137 ops/sec [33,536..46,041] → 57,417 ops/sec [56,595..57,585] 🟢 +46.7% 53,819 ops/sec [51,512..73,964] → 81,969 ops/sec [75,398..121,617] 🟢 +52.3%
nested array destructuring 14,590 ops/sec [14,359..18,030] → 24,004 ops/sec [23,847..26,546] 🟢 +64.5% 18,873 ops/sec [15,498..24,416] → 27,795 ops/sec [27,192..28,051] 🟢 +47.3%
swap variables 47,208 ops/sec [36,798..47,250] → 72,360 ops/sec [69,528..73,877] 🟢 +53.3% 75,541 ops/sec [57,221..90,482] → 117,862 ops/sec [112,090..130,430] 🟢 +56.0%
simple object destructuring 43,450 ops/sec [35,636..44,177] → 62,285 ops/sec [61,901..66,124] 🟢 +43.3% 75,878 ops/sec [67,737..78,940] → 104,252 ops/sec [99,260..108,391] 🟢 +37.4%
with defaults 47,399 ops/sec [43,295..56,618] → 66,975 ops/sec [66,296..67,354] 🟢 +41.3% 90,853 ops/sec [82,976..99,887] → 133,386 ops/sec [132,505..138,446] 🟢 +46.8%
with renaming 48,519 ops/sec [44,580..55,466] → 68,521 ops/sec [68,324..68,822] 🟢 +41.2% 74,704 ops/sec [61,692..114,447] → 129,227 ops/sec [118,682..133,965] 🟢 +73.0%
nested object destructuring 28,574 ops/sec [26,457..32,528] → 40,414 ops/sec [39,963..41,172] 🟢 +41.4% 39,779 ops/sec [31,624..45,222] → 59,570 ops/sec [58,977..72,311] 🟢 +49.8%
rest properties 23,384 ops/sec [20,929..27,373] → 35,229 ops/sec [34,954..35,295] 🟢 +50.7% 26,485 ops/sec [22,845..28,863] → 43,521 ops/sec [43,015..49,544] 🟢 +64.3%
object parameter 15,487 ops/sec [13,973..17,629] → 22,340 ops/sec [21,296..22,506] 🟢 +44.3% 27,977 ops/sec [22,813..43,354] → 47,098 ops/sec [46,621..49,417] 🟢 +68.3%
array parameter 19,480 ops/sec [16,197..24,437] → 25,229 ops/sec [24,857..25,349] 🟢 +29.5% 22,527 ops/sec [20,433..24,484] → 40,198 ops/sec [37,944..41,527] 🟢 +78.4%
mixed destructuring in map 4,128 ops/sec [2,868..4,205] → 6,141 ops/sec [6,102..6,252] 🟢 +48.8% 4,840 ops/sec [4,280..5,366] → 8,865 ops/sec [8,564..8,926] 🟢 +83.2%
forEach with array destructuring 8,596 ops/sec [7,821..10,067] → 11,523 ops/sec [11,341..11,616] 🟢 +34.1% 9,197 ops/sec [8,618..9,819] → 14,036 ops/sec [13,440..14,923] 🟢 +52.6%
map with array destructuring 9,056 ops/sec [5,101..10,653] → 11,892 ops/sec [11,726..11,929] 🟢 +31.3% 9,798 ops/sec [9,198..10,699] → 12,021 ops/sec [11,981..12,175] 🟢 +22.7%
filter with array destructuring 9,144 ops/sec [8,128..9,410] → 12,354 ops/sec [12,290..12,420] 🟢 +35.1% 11,651 ops/sec [8,871..12,244] → 12,909 ops/sec [12,692..14,488] 🟢 +10.8%
reduce with array destructuring 10,731 ops/sec [8,650..10,985] → 13,959 ops/sec [13,748..14,086] 🟢 +30.1% 10,116 ops/sec [9,538..10,818] → 14,073 ops/sec [12,176..14,235] 🟢 +39.1%
map with object destructuring 9,609 ops/sec [8,705..10,937] → 13,894 ops/sec [13,575..14,278] 🟢 +44.6% 13,128 ops/sec [6,395..14,001] → 15,997 ops/sec [15,755..16,145] 🟢 +21.9%
map with nested destructuring 7,725 ops/sec [7,071..10,197] → 11,299 ops/sec [11,124..11,589] 🟢 +46.3% 11,965 ops/sec [11,256..13,410] → 16,509 ops/sec [16,482..16,523] 🟢 +38.0%
map with rest in destructuring 4,227 ops/sec [3,735..5,760] → 6,598 ops/sec [6,556..6,754] 🟢 +56.1% 4,504 ops/sec [3,983..4,641] → 6,409 ops/sec [6,354..6,424] 🟢 +42.3%
map with defaults in destructuring 5,641 ops/sec [4,645..5,699] → 8,518 ops/sec [7,841..8,912] 🟢 +51.0% 10,460 ops/sec [10,300..10,721] → 14,064 ops/sec [13,899..14,186] 🟢 +34.5%
fibonacci.js — Interp: 🟢 8 · avg +50.9% · Bytecode: 🟢 8 · avg +60.2%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
recursive fib(15) 56 ops/sec [48..61] → 86 ops/sec [85..88] 🟢 +52.1% 1,191 ops/sec [1,058..1,499] → 1,733 ops/sec [1,686..1,993] 🟢 +45.6%
recursive fib(20) 5 ops/sec [5..5] → 8 ops/sec [8..9] 🟢 +62.2% 109 ops/sec [97..117] → 157 ops/sec [155..160] 🟢 +44.9%
recursive fib(15) typed 56 ops/sec [53..58] → 87 ops/sec [87..88] 🟢 +54.8% 964 ops/sec [849..1,049] → 1,594 ops/sec [1,565..1,620] 🟢 +65.4%
recursive fib(20) typed 6 ops/sec [5..6] → 8 ops/sec [8..9] 🟢 +43.1% 100 ops/sec [70..132] → 151 ops/sec [142..174] 🟢 +51.1%
iterative fib(20) via reduce 2,401 ops/sec [2,226..2,860] → 4,046 ops/sec [3,787..4,381] 🟢 +68.6% 3,012 ops/sec [2,364..4,167] → 5,068 ops/sec [5,035..5,285] 🟢 +68.2%
iterator fib(20) 1,307 ops/sec [1,157..1,649] → 1,969 ops/sec [1,934..2,005] 🟢 +50.6% 2,902 ops/sec [2,476..3,539] → 4,966 ops/sec [4,801..5,096] 🟢 +71.1%
iterator fib(20) via Iterator.from + take 1,510 ops/sec [1,422..1,813] → 1,947 ops/sec [1,877..2,024] 🟢 +28.9% 1,740 ops/sec [1,576..1,827] → 2,765 ops/sec [2,664..2,871] 🟢 +58.9%
iterator fib(20) last value via reduce 1,209 ops/sec [1,059..1,448] → 1,778 ops/sec [1,623..1,820] 🟢 +47.1% 1,219 ops/sec [1,171..1,503] → 2,152 ops/sec [2,140..2,193] 🟢 +76.6%
float16array.js — Interp: 🟢 32 · avg +38.3% · Bytecode: 🟢 31, 1 unch. · avg +55.1%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
new Float16Array(0) 62,557 ops/sec [58,371..66,016] → 87,876 ops/sec [87,481..88,663] 🟢 +40.5% 64,088 ops/sec [57,376..78,647] → 106,459 ops/sec [102,161..108,122] 🟢 +66.1%
new Float16Array(100) 58,448 ops/sec [41,288..59,316] → 84,398 ops/sec [84,368..84,502] 🟢 +44.4% 61,821 ops/sec [51,560..73,950] → 102,956 ops/sec [100,431..106,350] 🟢 +66.5%
new Float16Array(1000) 54,664 ops/sec [51,436..54,966] → 77,372 ops/sec [76,984..77,554] 🟢 +41.5% 48,744 ops/sec [42,989..52,108] → 89,037 ops/sec [87,373..91,050] 🟢 +82.7%
Float16Array.from([...100]) 939 ops/sec [832..1,090] → 1,264 ops/sec [1,260..1,266] 🟢 +34.6% 795 ops/sec [639..822] → 1,252 ops/sec [1,213..1,261] 🟢 +57.4%
Float16Array.of(1.5, 2.5, 3.5, 4.5, 5.5) 43,440 ops/sec [36,562..52,223] → 61,160 ops/sec [60,955..61,607] 🟢 +40.8% 34,458 ops/sec [33,600..40,167] → 62,157 ops/sec [61,926..63,694] 🟢 +80.4%
new Float16Array(float64Array) 20,252 ops/sec [18,345..20,564] → 25,269 ops/sec [25,044..27,677] 🟢 +24.8% 22,702 ops/sec [21,310..24,257] → 30,111 ops/sec [29,493..30,293] 🟢 +32.6%
sequential write 100 elements 627 ops/sec [552..728] → 937 ops/sec [934..940] 🟢 +49.4% 4,447 ops/sec [3,899..4,978] → 6,517 ops/sec [6,205..6,646] 🟢 +46.6%
sequential read 100 elements 641 ops/sec [638..783] → 1,022 ops/sec [999..1,069] 🟢 +59.5% 4,771 ops/sec [4,454..5,687] → 7,894 ops/sec [7,846..8,015] 🟢 +65.4%
write special values (NaN, Inf, -0) 28,484 ops/sec [26,597..28,616] → 43,171 ops/sec [43,000..43,331] 🟢 +51.6% 243,502 ops/sec [211,662..246,204] → 246,992 ops/sec [202,857..344,083] ~ overlap (+1.4%)
Float16Array write 620 ops/sec [608..624] → 904 ops/sec [902..908] 🟢 +45.8% 4,533 ops/sec [4,083..4,654] → 6,537 ops/sec [6,024..8,034] 🟢 +44.2%
Float32Array write 624 ops/sec [532..704] → 925 ops/sec [909..934] 🟢 +48.4% 3,804 ops/sec [3,736..3,806] → 6,324 ops/sec [6,148..6,530] 🟢 +66.3%
Float64Array write 648 ops/sec [517..719] → 915 ops/sec [902..925] 🟢 +41.2% 4,321 ops/sec [4,296..4,357] → 6,443 ops/sec [6,275..6,624] 🟢 +49.1%
Float16Array read 626 ops/sec [335..781] → 982 ops/sec [950..1,037] 🟢 +56.9% 5,636 ops/sec [5,227..6,003] → 7,904 ops/sec [7,844..8,099] 🟢 +40.3%
Float32Array read 644 ops/sec [590..707] → 986 ops/sec [977..992] 🟢 +53.2% 5,660 ops/sec [5,582..5,743] → 8,080 ops/sec [7,878..8,119] 🟢 +42.8%
Float64Array read 719 ops/sec [664..818] → 999 ops/sec [985..1,099] 🟢 +38.9% 5,617 ops/sec [4,816..6,134] → 8,022 ops/sec [7,999..8,152] 🟢 +42.8%
fill(1.5) 5,288 ops/sec [5,212..5,399] → 7,043 ops/sec [6,906..7,088] 🟢 +33.2% 5,672 ops/sec [5,576..5,717] → 7,971 ops/sec [7,892..8,306] 🟢 +40.5%
slice() 34,089 ops/sec [32,967..34,915] → 47,628 ops/sec [47,109..47,966] 🟢 +39.7% 33,957 ops/sec [28,809..34,207] → 52,377 ops/sec [49,920..57,074] 🟢 +54.2%
map(x => x * 2) 1,347 ops/sec [1,316..1,380] → 1,960 ops/sec [1,919..1,971] 🟢 +45.5% 1,269 ops/sec [1,114..1,499] → 1,882 ops/sec [1,726..2,098] 🟢 +48.3%
filter(x => x > 25) 1,400 ops/sec [826..1,558] → 1,896 ops/sec [1,842..1,970] 🟢 +35.5% 1,322 ops/sec [1,271..1,400] → 1,842 ops/sec [1,831..1,851] 🟢 +39.4%
reduce (sum) 1,393 ops/sec [1,298..1,506] → 1,926 ops/sec [1,912..2,055] 🟢 +38.3% 1,238 ops/sec [1,161..1,245] → 1,768 ops/sec [1,658..1,807] 🟢 +42.9%
sort() 17,293 ops/sec [16,248..19,008] → 20,664 ops/sec [20,253..20,963] 🟢 +19.5% 15,087 ops/sec [14,383..15,960] → 22,177 ops/sec [21,751..22,561] 🟢 +47.0%
indexOf() 16,765 ops/sec [15,118..18,008] → 23,750 ops/sec [23,551..24,103] 🟢 +41.7% 14,297 ops/sec [11,462..17,081] → 26,117 ops/sec [24,978..28,295] 🟢 +82.7%
reverse() 25,449 ops/sec [21,221..27,008] → 28,268 ops/sec [28,149..29,382] 🟢 +11.1% 21,216 ops/sec [17,195..24,522] → 32,932 ops/sec [32,360..32,974] 🟢 +55.2%
toReversed() 22,429 ops/sec [20,275..23,416] → 25,333 ops/sec [25,103..28,962] 🟢 +13.0% 19,975 ops/sec [15,808..25,603] → 29,723 ops/sec [29,545..30,006] 🟢 +48.8%
toSorted() 9,838 ops/sec [9,047..9,862] → 12,620 ops/sec [12,503..12,661] 🟢 +28.3% 9,569 ops/sec [7,679..12,174] → 14,333 ops/sec [14,312..16,207] 🟢 +49.8%
create view over existing buffer 82,491 ops/sec [75,645..90,588] → 102,204 ops/sec [100,318..105,222] 🟢 +23.9% 83,017 ops/sec [73,884..99,312] → 134,184 ops/sec [129,894..136,655] 🟢 +61.6%
subarray() 37,197 ops/sec [35,330..41,679] → 51,572 ops/sec [50,930..53,855] 🟢 +38.6% 30,932 ops/sec [27,487..37,536] → 58,044 ops/sec [56,138..58,534] 🟢 +87.7%
set() from array 49,130 ops/sec [43,046..58,821] → 61,362 ops/sec [60,405..61,613] 🟢 +24.9% 40,998 ops/sec [34,227..48,412] → 72,732 ops/sec [70,221..73,566] 🟢 +77.4%
for-of loop 936 ops/sec [791..1,100] → 1,366 ops/sec [1,361..1,388] 🟢 +45.9% 5,237 ops/sec [4,119..6,383] → 9,072 ops/sec [8,906..9,202] 🟢 +73.2%
spread into array 4,401 ops/sec [3,784..4,721] → 5,655 ops/sec [5,620..5,675] 🟢 +28.5% 11,508 ops/sec [9,164..13,005] → 18,102 ops/sec [17,356..18,435] 🟢 +57.3%
f16round(1.337) 94,723 ops/sec [93,919..100,346] → 139,805 ops/sec [137,756..140,581] 🟢 +47.6% 119,733 ops/sec [90,676..138,663] → 178,719 ops/sec [168,561..199,924] 🟢 +49.3%
f16round over 100 values 615 ops/sec [535..712] → 856 ops/sec [849..893] 🟢 +39.3% 1,364 ops/sec [1,179..1,733] → 2,219 ops/sec [2,209..2,234] 🟢 +62.7%
for-in/for-in.js — Interp: 🟢 3 · avg +41.5% · Bytecode: 🟢 3 · avg +59.4%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
for...in over 50 own keys 1,510 ops/sec [1,421..1,699] → 2,319 ops/sec [2,288..2,528] 🟢 +53.6% 1,872 ops/sec [1,574..2,099] → 3,238 ops/sec [3,160..3,299] 🟢 +73.0%
for...in over an 8-level chain of 50 shared keys 1,109 ops/sec [995..1,215] → 1,499 ops/sec [1,469..1,733] 🟢 +35.1% 1,228 ops/sec [1,219..1,236] → 2,136 ops/sec [2,034..2,461] 🟢 +74.0%
for...in over a 16-level chain of 100 shared keys 382 ops/sec [354..434] → 519 ops/sec [515..520] 🟢 +35.8% 571 ops/sec [494..691] → 749 ops/sec [739..765] 🟢 +31.2%
for-of.js — Interp: 🟢 7 · avg +31.8% · Bytecode: 🟢 7 · avg +38.5%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
for...of with 10-element array 8,102 ops/sec [7,550..9,134] → 11,087 ops/sec [10,766..11,197] 🟢 +36.8% 58,226 ops/sec [57,549..61,592] → 83,189 ops/sec [82,445..83,922] 🟢 +42.9%
for...of with 100-element array 999 ops/sec [829..1,234] → 1,320 ops/sec [1,311..1,322] 🟢 +32.1% 9,942 ops/sec [8,836..10,327] → 13,084 ops/sec [13,003..13,182] 🟢 +31.6%
for...of with string (10 chars) 6,200 ops/sec [5,218..6,786] → 7,950 ops/sec [7,925..7,981] 🟢 +28.2% 10,407 ops/sec [9,277..12,626] → 16,338 ops/sec [16,142..16,806] 🟢 +57.0%
for...of with Set (10 elements) 9,137 ops/sec [7,850..9,968] → 12,372 ops/sec [12,177..12,488] 🟢 +35.4% 99,142 ops/sec [87,771..99,566] → 121,786 ops/sec [120,031..122,937] 🟢 +22.8%
for...of with Map entries (10 entries) 4,676 ops/sec [4,513..4,764] → 6,244 ops/sec [6,084..8,394] 🟢 +33.5% 8,619 ops/sec [7,835..9,651] → 11,483 ops/sec [11,164..12,003] 🟢 +33.2%
for...of with destructuring 5,069 ops/sec [4,649..5,645] → 6,675 ops/sec [6,614..6,752] 🟢 +31.7% 10,805 ops/sec [9,908..11,112] → 13,451 ops/sec [13,010..13,684] 🟢 +24.5%
for-await-of with sync array 6,991 ops/sec [6,372..7,351] → 8,748 ops/sec [7,578..9,289] 🟢 +25.1% 1,106 ops/sec [1,077..1,108] → 1,744 ops/sec [1,719..1,807] 🟢 +57.6%
generators.js — Interp: 🟢 4 · avg +21.2% · Bytecode: 🟢 4 · avg +30.4%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
manual next over object generator 445 ops/sec [426..462] → 575 ops/sec [565..602] 🟢 +29.1% 697 ops/sec [665..706] → 865 ops/sec [855..1,024] 🟢 +24.2%
for...of over object generator 657 ops/sec [500..809] → 833 ops/sec [832..836] 🟢 +26.9% 950 ops/sec [840..1,007] → 1,346 ops/sec [1,343..1,348] 🟢 +41.7%
yield delegation 722 ops/sec [702..726] → 823 ops/sec [815..910] 🟢 +14.1% 1,132 ops/sec [844..1,222] → 1,374 ops/sec [1,274..1,517] 🟢 +21.3%
class generator method 716 ops/sec [661..786] → 822 ops/sec [816..823] 🟢 +14.7% 999 ops/sec [891..1,302] → 1,344 ops/sec [1,306..1,470] 🟢 +34.5%
intl.js — Interp: 🟢 6 · avg +30.6% · Bytecode: 🟢 6 · avg +47.9%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
format decimal 18,487 ops/sec [18,034..19,270] → 23,378 ops/sec [22,746..26,081] 🟢 +26.5% 16,927 ops/sec [15,907..17,584] → 23,488 ops/sec [23,223..23,708] 🟢 +38.8%
format currency 15,932 ops/sec [13,682..17,245] → 19,311 ops/sec [19,151..19,343] 🟢 +21.2% 11,276 ops/sec [11,152..11,302] → 19,485 ops/sec [18,933..22,413] 🟢 +72.8%
format UTC date 6,139 ops/sec [5,695..6,698] → 9,173 ops/sec [8,492..9,214] 🟢 +49.4% 5,854 ops/sec [5,748..5,925] → 8,469 ops/sec [8,070..8,526] 🟢 +44.7%
formatRange UTC dates 2,291 ops/sec [1,986..2,499] → 2,812 ops/sec [2,798..3,117] 🟢 +22.8% 1,916 ops/sec [1,826..2,090] → 2,699 ops/sec [2,664..2,735] 🟢 +40.9%
compare numeric strings 62,728 ops/sec [52,572..65,357] → 86,433 ops/sec [81,591..86,818] 🟢 +37.8% 70,467 ops/sec [64,790..75,951] → 104,657 ops/sec [104,374..104,902] 🟢 +48.5%
sort short string list 11,896 ops/sec [10,765..13,114] → 14,989 ops/sec [14,857..16,083] 🟢 +26.0% 10,841 ops/sec [9,192..11,811] → 15,388 ops/sec [15,192..15,926] 🟢 +41.9%
iterators.js — Interp: 🟢 42 · avg +44.5% · Bytecode: 🟢 41, 1 unch. · avg +39.8%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
Iterator.from({next}).toArray() — 20 elements 2,332 ops/sec [2,135..2,494] → 3,069 ops/sec [3,030..3,121] 🟢 +31.6% 3,573 ops/sec [3,551..3,581] → 4,795 ops/sec [4,758..4,820] 🟢 +34.2%
Iterator.from({next}).toArray() — 50 elements 1,066 ops/sec [910..1,112] → 1,312 ops/sec [1,291..1,379] 🟢 +23.1% 1,605 ops/sec [1,465..1,792] → 2,100 ops/sec [2,098..2,172] 🟢 +30.9%
spread pre-wrapped iterator — 20 elements 2,251 ops/sec [2,120..2,453] → 2,765 ops/sec [2,665..2,788] 🟢 +22.9% 4,211 ops/sec [3,811..4,479] → 5,185 ops/sec [5,108..5,201] 🟢 +23.2%
Iterator.from({next}).forEach — 50 elements 749 ops/sec [624..781] → 908 ops/sec [884..920] 🟢 +21.2% 1,118 ops/sec [1,102..1,179] → 1,446 ops/sec [1,409..1,461] 🟢 +29.4%
Iterator.from({next}).reduce — 50 elements 787 ops/sec [745..790] → 1,007 ops/sec [981..1,023] 🟢 +27.9% 1,127 ops/sec [1,057..1,138] → 1,377 ops/sec [1,365..1,391] 🟢 +22.2%
wrap array iterator 10,677 ops/sec [9,361..10,865] → 12,996 ops/sec [12,604..13,097] 🟢 +21.7% 9,309 ops/sec [9,002..10,085] → 14,316 ops/sec [13,622..15,171] 🟢 +53.8%
wrap plain {next()} object 1,647 ops/sec [1,466..1,815] → 2,114 ops/sec [2,086..2,242] 🟢 +28.3% 2,426 ops/sec [2,217..2,452] → 3,364 ops/sec [3,330..4,284] 🟢 +38.7%
map + toArray (50 elements) 515 ops/sec [508..570] → 706 ops/sec [701..708] 🟢 +37.0% 703 ops/sec [634..871] → 909 ops/sec [902..1,099] 🟢 +29.2%
filter + toArray (50 elements) 594 ops/sec [494..633] → 755 ops/sec [726..804] 🟢 +27.1% 736 ops/sec [727..765] → 982 ops/sec [976..995] 🟢 +33.4%
take(10) + toArray (50 element source) 2,582 ops/sec [2,403..3,090] → 3,690 ops/sec [3,586..3,777] 🟢 +42.9% 3,681 ops/sec [3,545..3,997] → 4,996 ops/sec [4,930..5,019] 🟢 +35.7%
drop(40) + toArray (50 element source) 754 ops/sec [595..987] → 1,035 ops/sec [1,025..1,249] 🟢 +37.3% 980 ops/sec [900..1,270] → 1,488 ops/sec [1,479..1,511] 🟢 +51.8%
chained map + filter + take (100 element source) 822 ops/sec [751..863] → 1,089 ops/sec [1,080..1,161] 🟢 +32.4% 979 ops/sec [895..1,080] → 1,284 ops/sec [1,282..1,338] 🟢 +31.2%
some + every (50 elements) 361 ops/sec [305..435] → 625 ops/sec [531..795] 🟢 +73.1% 565 ops/sec [521..664] → 866 ops/sec [798..926] 🟢 +53.3%
find (50 elements) 850 ops/sec [639..966] → 1,217 ops/sec [1,198..1,282] 🟢 +43.2% 1,230 ops/sec [1,038..1,342] → 1,783 ops/sec [1,746..1,869] 🟢 +45.0%
concat 2 arrays (10 + 10 elements) 3,818 ops/sec [2,946..4,352] → 5,284 ops/sec [5,248..6,322] 🟢 +38.4% 3,546 ops/sec [3,433..4,125] → 5,148 ops/sec [5,049..5,194] 🟢 +45.2%
concat 5 arrays (10 elements each) 1,505 ops/sec [1,255..1,870] → 2,224 ops/sec [2,202..2,846] 🟢 +47.7% 1,416 ops/sec [1,301..1,559] → 2,247 ops/sec [2,233..2,252] 🟢 +58.7%
concat 2 arrays (20 + 20 elements) 1,956 ops/sec [1,711..2,399] → 2,800 ops/sec [2,778..3,269] 🟢 +43.1% 1,941 ops/sec [1,806..2,370] → 2,809 ops/sec [2,799..2,847] 🟢 +44.8%
concat + filter + toArray (20 + 20 elements) 859 ops/sec [842..864] → 1,259 ops/sec [1,248..1,266] 🟢 +46.5% 925 ops/sec [884..976] → 1,367 ops/sec [1,314..1,376] 🟢 +47.8%
concat + map + take (20 + 20 elements, take 10) 2,051 ops/sec [1,702..2,806] → 3,029 ops/sec [3,006..3,324] 🟢 +47.7% 2,208 ops/sec [1,969..2,471] → 3,135 ops/sec [3,111..3,254] 🟢 +42.0%
concat Sets (15 + 15 elements) 2,995 ops/sec [2,750..3,372] → 3,876 ops/sec [3,870..3,890] 🟢 +29.4% 3,017 ops/sec [3,000..3,126] → 3,982 ops/sec [3,862..4,097] 🟢 +32.0%
concat boxed strings (13 + 13 characters) 2,683 ops/sec [2,612..2,861] → 3,908 ops/sec [3,893..3,930] 🟢 +45.7% 3,081 ops/sec [2,745..3,470] → 3,921 ops/sec [3,882..3,962] 🟢 +27.3%
zip 2 arrays (10 + 10 elements) 7,009 ops/sec [6,809..7,813] → 9,130 ops/sec [9,084..9,218] 🟢 +30.3% 6,732 ops/sec [6,047..9,054] → 9,396 ops/sec [9,252..9,817] 🟢 +39.6%
zip 3 arrays (10 elements each) 6,343 ops/sec [5,856..6,675] → 8,827 ops/sec [8,524..9,118] 🟢 +39.2% 5,960 ops/sec [5,135..7,741] → 8,609 ops/sec [8,567..8,914] 🟢 +44.4%
zip 2 arrays (20 + 20 elements) 3,816 ops/sec [3,499..4,951] → 5,619 ops/sec [5,602..5,660] 🟢 +47.3% 4,341 ops/sec [3,744..5,336] → 5,614 ops/sec [5,533..5,656] 🟢 +29.3%
zip 2 arrays (50 + 50 elements) 2,003 ops/sec [1,298..2,140] → 2,504 ops/sec [2,475..2,710] 🟢 +25.0% 1,952 ops/sec [1,583..2,427] → 2,446 ops/sec [2,384..4,031] ~ overlap (+25.3%)
zip shortest mode (20 + 10 elements) 6,625 ops/sec [5,715..7,501] → 9,783 ops/sec [8,968..11,418] 🟢 +47.7% 7,521 ops/sec [7,454..7,616] → 9,124 ops/sec [8,953..9,500] 🟢 +21.3%
zip longest mode (10 + 20 elements) 3,432 ops/sec [3,001..3,939] → 5,363 ops/sec [5,342..5,972] 🟢 +56.3% 4,220 ops/sec [3,789..4,386] → 5,531 ops/sec [4,996..6,322] 🟢 +31.0%
zip strict mode (20 + 20 elements) 3,302 ops/sec [3,039..4,025] → 6,676 ops/sec [5,622..7,048] 🟢 +102.2% 3,611 ops/sec [3,406..4,244] → 5,356 ops/sec [5,216..5,441] 🟢 +48.3%
zip + map + toArray (20 + 20 elements) 1,150 ops/sec [985..1,274] → 1,829 ops/sec [1,803..1,903] 🟢 +59.0% 1,146 ops/sec [1,014..1,210] → 1,837 ops/sec [1,694..2,037] 🟢 +60.3%
zip + filter + toArray (20 + 20 elements) 1,396 ops/sec [1,197..1,404] → 2,093 ops/sec [1,980..2,344] 🟢 +50.0% 1,242 ops/sec [1,118..1,333] → 1,964 ops/sec [1,801..2,584] 🟢 +58.1%
zip Sets (15 + 15 elements) 5,408 ops/sec [4,415..6,568] → 7,869 ops/sec [7,654..8,398] 🟢 +45.5% 5,165 ops/sec [4,393..5,816] → 7,647 ops/sec [7,236..8,040] 🟢 +48.1%
zipKeyed 2 keys (10 elements each) 6,245 ops/sec [5,994..6,644] → 8,925 ops/sec [8,912..8,936] 🟢 +42.9% 5,763 ops/sec [5,625..7,266] → 8,896 ops/sec [8,645..9,608] 🟢 +54.4%
zipKeyed 3 keys (20 elements each) 3,031 ops/sec [2,616..3,032] → 4,887 ops/sec [4,622..5,315] 🟢 +61.3% 3,120 ops/sec [2,817..3,460] → 4,604 ops/sec [4,558..4,631] 🟢 +47.6%
zipKeyed longest mode (10 + 20 elements) 4,023 ops/sec [3,118..4,778] → 5,343 ops/sec [5,172..5,405] 🟢 +32.8% 4,008 ops/sec [3,474..4,189] → 5,197 ops/sec [5,031..5,586] 🟢 +29.7%
zipKeyed strict mode (20 + 20 elements) 3,389 ops/sec [3,286..4,524] → 5,270 ops/sec [5,219..5,650] 🟢 +55.5% 4,001 ops/sec [3,467..4,631] → 5,301 ops/sec [5,224..5,353] 🟢 +32.5%
zipKeyed + filter + map (20 elements) 1,150 ops/sec [1,083..1,399] → 1,759 ops/sec [1,672..1,951] 🟢 +53.0% 1,396 ops/sec [1,103..1,439] → 1,924 ops/sec [1,914..1,940] 🟢 +37.8%
array.values().map().filter().toArray() 464 ops/sec [456..467] → 699 ops/sec [687..725] 🟢 +50.6% 548 ops/sec [456..679] → 719 ops/sec [705..724] 🟢 +31.4%
array.values().take(5).toArray() 7,751 ops/sec [7,356..8,072] → 11,968 ops/sec [11,487..12,371] 🟢 +54.4% 8,999 ops/sec [7,374..10,765] → 11,738 ops/sec [11,638..11,847] 🟢 +30.4%
array.values().drop(45).toArray() 1,547 ops/sec [1,344..1,849] → 2,448 ops/sec [2,403..2,455] 🟢 +58.3% 1,670 ops/sec [1,119..2,075] → 2,408 ops/sec [2,385..2,428] 🟢 +44.2%
map.entries() chained helpers 595 ops/sec [533..785] → 943 ops/sec [923..947] 🟢 +58.4% 614 ops/sec [579..801] → 948 ops/sec [901..996] 🟢 +54.3%
set.values() chained helpers 1,072 ops/sec [912..1,452] → 1,760 ops/sec [1,743..2,218] 🟢 +64.2% 1,188 ops/sec [1,121..1,237] → 1,755 ops/sec [1,704..1,773] 🟢 +47.8%
string iterator map + toArray 967 ops/sec [846..1,042] → 1,603 ops/sec [1,584..1,688] 🟢 +65.7% 1,111 ops/sec [921..1,387] → 1,611 ops/sec [1,588..1,713] 🟢 +45.0%
json.js — Interp: 🟢 23 · avg +41.9% · Bytecode: 🟢 22, 1 unch. · avg +50.9%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
parse simple object 35,318 ops/sec [33,333..35,458] → 41,246 ops/sec [41,151..43,885] 🟢 +16.8% 34,802 ops/sec [32,640..37,136] → 48,666 ops/sec [48,242..49,227] 🟢 +39.8%
parse nested object 22,101 ops/sec [20,756..22,446] → 26,515 ops/sec [26,458..26,756] 🟢 +20.0% 21,906 ops/sec [19,812..23,099] → 30,424 ops/sec [29,461..30,960] 🟢 +38.9%
parse array of objects 12,584 ops/sec [11,225..12,654] → 14,931 ops/sec [14,880..15,012] 🟢 +18.7% 12,305 ops/sec [12,248..12,395] → 16,918 ops/sec [16,694..17,190] 🟢 +37.5%
parse large flat object 13,189 ops/sec [12,446..14,662] → 16,610 ops/sec [16,545..20,355] 🟢 +25.9% 13,448 ops/sec [13,399..13,638] → 18,411 ops/sec [17,913..20,028] 🟢 +36.9%
parse mixed types 10,940 ops/sec [9,540..12,207] → 13,138 ops/sec [12,914..16,114] 🟢 +20.1% 9,699 ops/sec [8,553..10,620] → 14,607 ops/sec [14,490..14,656] 🟢 +50.6%
stringify simple object 27,976 ops/sec [25,847..33,788] → 42,009 ops/sec [41,273..42,533] 🟢 +50.2% 30,948 ops/sec [30,483..35,209] → 45,292 ops/sec [43,750..46,614] 🟢 +46.3%
stringify nested object 16,607 ops/sec [13,652..18,476] → 24,568 ops/sec [24,320..24,928] 🟢 +47.9% 17,677 ops/sec [17,349..17,937] → 26,103 ops/sec [25,794..28,672] 🟢 +47.7%
stringify array of objects 8,484 ops/sec [6,243..9,793] → 10,803 ops/sec [10,627..10,939] 🟢 +27.3% 7,741 ops/sec [6,652..10,396] → 11,894 ops/sec [11,339..12,506] 🟢 +53.6%
stringify mixed types 15,965 ops/sec [14,492..16,893] → 21,187 ops/sec [20,913..26,824] 🟢 +32.7% 14,773 ops/sec [14,623..14,923] → 22,178 ops/sec [21,633..22,645] 🟢 +50.1%
reviver doubles numbers 5,005 ops/sec [4,133..6,086] → 7,399 ops/sec [7,281..7,438] 🟢 +47.8% 6,924 ops/sec [5,378..7,818] → 10,404 ops/sec [10,382..10,579] 🟢 +50.3%
reviver filters properties 5,317 ops/sec [4,975..6,562] → 7,670 ops/sec [7,611..7,806] 🟢 +44.3% 6,537 ops/sec [5,291..6,758] → 9,539 ops/sec [9,325..9,691] 🟢 +45.9%
reviver on nested object 5,718 ops/sec [5,072..6,006] → 8,778 ops/sec [8,631..8,848] 🟢 +53.5% 7,849 ops/sec [7,655..7,897] → 11,263 ops/sec [10,904..11,490] 🟢 +43.5%
reviver on array 2,945 ops/sec [2,364..3,416] → 4,652 ops/sec [4,612..6,775] 🟢 +58.0% 4,796 ops/sec [3,999..5,164] → 6,807 ops/sec [6,726..6,844] 🟢 +41.9%
replacer function doubles numbers 5,539 ops/sec [4,953..6,112] → 8,711 ops/sec [8,609..9,478] 🟢 +57.3% 7,676 ops/sec [6,921..9,414] → 12,929 ops/sec [12,665..12,999] 🟢 +68.4%
replacer function excludes properties 7,440 ops/sec [6,443..7,554] → 11,588 ops/sec [11,549..11,709] 🟢 +55.8% 9,961 ops/sec [8,155..14,222] → 17,756 ops/sec [17,605..17,811] 🟢 +78.3%
array replacer (allowlist) 21,111 ops/sec [19,485..26,667] → 33,440 ops/sec [33,014..37,742] 🟢 +58.4% 24,215 ops/sec [17,972..26,105] → 35,861 ops/sec [35,743..35,937] 🟢 +48.1%
stringify with 2-space indent 16,614 ops/sec [15,955..16,622] → 25,522 ops/sec [24,988..25,680] 🟢 +53.6% 19,317 ops/sec [13,885..19,585] → 26,502 ops/sec [26,344..27,523] 🟢 +37.2%
stringify with tab indent 16,924 ops/sec [16,163..19,377] → 25,638 ops/sec [24,934..26,922] 🟢 +51.5% 17,743 ops/sec [14,971..20,204] → 27,039 ops/sec [26,899..27,333] 🟢 +52.4%
stringify deeply nested object with 2-space indent 2,669 ops/sec [2,441..3,070] → 3,902 ops/sec [3,823..4,272] 🟢 +46.2% 2,602 ops/sec [2,225..2,889] → 4,176 ops/sec [3,809..5,376] 🟢 +60.5%
stringify deeply nested array with 2-space indent 3,713 ops/sec [3,545..3,825] → 5,474 ops/sec [5,433..5,492] 🟢 +47.4% 3,458 ops/sec [3,208..4,328] → 5,475 ops/sec [5,309..5,887] 🟢 +58.3%
stringify very deeply nested object with 2-space indent 476 ops/sec [385..624] → 654 ops/sec [652..669] 🟢 +37.5% 437 ops/sec [380..575] → 637 ops/sec [563..807] ~ overlap (+45.5%)
parse then stringify 8,724 ops/sec [7,429..11,811] → 13,151 ops/sec [12,966..13,323] 🟢 +50.7% 8,586 ops/sec [7,051..14,132] → 15,588 ops/sec [14,239..17,347] 🟢 +81.6%
stringify then parse 5,735 ops/sec [4,457..6,387] → 8,091 ops/sec [8,034..8,821] 🟢 +41.1% 5,483 ops/sec [4,732..6,583] → 8,685 ops/sec [8,565..10,628] 🟢 +58.4%
jsx.jsx — Interp: 🟢 21 · avg +49.8% · Bytecode: 🟢 21 · avg +37.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
simple element 48,763 ops/sec [42,080..55,421] → 71,773 ops/sec [71,521..72,987] 🟢 +47.2% 81,510 ops/sec [77,220..82,358] → 100,900 ops/sec [97,823..131,924] 🟢 +23.8%
self-closing element 50,810 ops/sec [45,797..52,687] → 71,897 ops/sec [70,664..73,149] 🟢 +41.5% 68,482 ops/sec [65,885..69,875] → 102,715 ops/sec [100,791..105,550] 🟢 +50.0%
element with string attribute 40,235 ops/sec [34,122..49,339] → 60,132 ops/sec [59,396..60,260] 🟢 +49.5% 62,289 ops/sec [56,361..65,221] → 78,057 ops/sec [77,439..79,689] 🟢 +25.3%
element with multiple attributes 34,489 ops/sec [31,043..36,776] → 51,599 ops/sec [51,103..54,675] 🟢 +49.6% 47,272 ops/sec [42,764..51,326] → 64,429 ops/sec [62,278..66,544] 🟢 +36.3%
element with expression attribute 36,300 ops/sec [33,276..39,095] → 53,972 ops/sec [51,981..64,896] 🟢 +48.7% 62,365 ops/sec [58,996..63,932] → 80,558 ops/sec [79,659..81,896] 🟢 +29.2%
text child 46,694 ops/sec [42,011..50,017] → 69,981 ops/sec [69,243..91,766] 🟢 +49.9% 78,779 ops/sec [73,913..84,991] → 101,681 ops/sec [98,557..104,050] 🟢 +29.1%
expression child 42,884 ops/sec [40,304..45,623] → 62,598 ops/sec [62,444..91,654] 🟢 +46.0% 67,523 ops/sec [63,248..78,576] → 98,048 ops/sec [97,114..98,597] 🟢 +45.2%
mixed text and expression 37,757 ops/sec [33,294..43,432] → 58,903 ops/sec [58,699..59,139] 🟢 +56.0% 68,674 ops/sec [65,456..77,200] → 94,279 ops/sec [92,788..94,984] 🟢 +37.3%
nested elements (3 levels) 20,675 ops/sec [17,681..20,843] → 28,722 ops/sec [28,302..28,729] 🟢 +38.9% 29,307 ops/sec [26,678..32,649] → 39,505 ops/sec [38,676..40,309] 🟢 +34.8%
sibling children 15,840 ops/sec [14,768..16,211] → 21,415 ops/sec [21,335..21,493] 🟢 +35.2% 23,832 ops/sec [22,930..24,594] → 29,107 ops/sec [29,040..29,181] 🟢 +22.1%
component element 37,330 ops/sec [32,461..37,856] → 52,600 ops/sec [49,733..56,373] 🟢 +40.9% 47,275 ops/sec [40,255..54,931] → 71,164 ops/sec [70,837..78,299] 🟢 +50.5%
component with children 22,248 ops/sec [20,208..24,982] → 34,255 ops/sec [32,177..34,686] 🟢 +54.0% 29,780 ops/sec [27,970..31,826] → 45,438 ops/sec [45,079..45,684] 🟢 +52.6%
dotted component 28,034 ops/sec [25,672..32,039] → 43,155 ops/sec [42,621..46,248] 🟢 +53.9% 38,712 ops/sec [32,931..47,337] → 58,302 ops/sec [57,231..68,414] 🟢 +50.6%
empty fragment 48,262 ops/sec [38,861..54,768] → 74,079 ops/sec [72,991..78,442] 🟢 +53.5% 71,921 ops/sec [63,319..83,221] → 106,708 ops/sec [102,309..132,950] 🟢 +48.4%
fragment with children 13,245 ops/sec [12,248..15,104] → 21,303 ops/sec [20,547..21,736] 🟢 +60.8% 23,076 ops/sec [19,276..29,174] → 29,434 ops/sec [29,218..30,092] 🟢 +27.6%
spread attributes 22,105 ops/sec [20,574..25,629] → 32,971 ops/sec [32,666..33,089] 🟢 +49.2% 27,812 ops/sec [27,679..28,018] → 38,784 ops/sec [37,882..39,095] 🟢 +39.4%
spread with overrides 19,458 ops/sec [17,190..21,142] → 28,866 ops/sec [28,648..29,082] 🟢 +48.4% 25,008 ops/sec [21,177..25,836] → 34,489 ops/sec [33,023..34,741] 🟢 +37.9%
shorthand props 32,727 ops/sec [29,088..35,356] → 48,190 ops/sec [47,812..49,585] 🟢 +47.2% 51,186 ops/sec [42,852..58,834] → 71,591 ops/sec [71,172..73,136] 🟢 +39.9%
nav bar structure 7,065 ops/sec [5,390..9,008] → 10,936 ops/sec [10,540..13,040] 🟢 +54.8% 10,570 ops/sec [8,241..10,776] → 13,528 ops/sec [13,262..15,373] 🟢 +28.0%
card component tree 7,980 ops/sec [6,935..9,416] → 12,360 ops/sec [12,158..12,429] 🟢 +54.9% 11,792 ops/sec [11,730..12,231] → 16,442 ops/sec [15,220..19,301] 🟢 +39.4%
10 list items via Array.from 3,103 ops/sec [2,891..4,026] → 5,161 ops/sec [4,955..5,629] 🟢 +66.3% 4,038 ops/sec [3,971..4,056] → 5,459 ops/sec [5,154..5,969] 🟢 +35.2%
modules.js — Interp: 🟢 9 · avg +47.9% · Bytecode: 🔴 1, 8 unch. · avg -6.5%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
call imported function 69,666 ops/sec [66,560..78,685] → 109,517 ops/sec [109,022..110,049] 🟢 +57.2% 339,120 ops/sec [325,941..347,378] → 327,548 ops/sec [309,322..383,801] ~ overlap (-3.4%)
call two imported functions 37,579 ops/sec [33,690..39,566] → 60,457 ops/sec [59,727..60,860] 🟢 +60.9% 226,987 ops/sec [200,122..227,495] → 205,032 ops/sec [200,556..216,705] ~ overlap (-9.7%)
read imported constant 179,222 ops/sec [165,487..194,860] → 264,382 ops/sec [262,878..289,287] 🟢 +47.5% 486,669 ops/sec [467,858..575,468] → 437,582 ops/sec [402,865..462,230] 🔴 -10.1%
read imported string 178,170 ops/sec [174,685..197,052] → 264,328 ops/sec [260,230..283,097] 🟢 +48.4% 465,014 ops/sec [460,805..531,454] → 448,316 ops/sec [432,712..489,006] ~ overlap (-3.6%)
read JSON string property 175,931 ops/sec [170,704..179,753] → 266,540 ops/sec [257,817..284,756] 🟢 +51.5% 471,358 ops/sec [469,056..471,604] → 458,591 ops/sec [428,062..539,897] ~ overlap (-2.7%)
read JSON number property 172,844 ops/sec [146,200..209,360] → 259,329 ops/sec [250,325..264,450] 🟢 +50.0% 498,084 ops/sec [454,923..569,145] → 484,758 ops/sec [412,829..628,317] ~ overlap (-2.7%)
read JSON boolean property 187,719 ops/sec [163,884..216,460] → 263,375 ops/sec [257,311..314,180] 🟢 +40.3% 512,262 ops/sec [491,554..540,745] → 466,339 ops/sec [425,688..531,892] ~ overlap (-9.0%)
read JSON array property 186,980 ops/sec [152,558..213,515] → 265,836 ops/sec [262,846..274,488] 🟢 +42.2% 482,993 ops/sec [475,329..670,589] → 460,863 ops/sec [417,356..528,408] ~ overlap (-4.6%)
read multiple JSON properties 93,277 ops/sec [90,050..95,608] → 124,237 ops/sec [123,372..124,664] 🟢 +33.2% 350,555 ops/sec [333,983..407,969] → 306,294 ops/sec [299,020..442,597] ~ overlap (-12.6%)
numbers.js — Interp: 🟢 12 · avg +62.1% · Bytecode: 🟢 10, 🔴 1, 1 unch. · avg +57.1%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
integer arithmetic 41,359 ops/sec [38,138..50,091] → 63,925 ops/sec [62,731..64,695] 🟢 +54.6% 399,876 ops/sec [394,588..400,091] → 377,711 ops/sec [368,343..384,495] 🔴 -5.5%
floating point arithmetic 53,935 ops/sec [39,906..57,407] → 76,377 ops/sec [75,199..103,735] 🟢 +41.6% 330,637 ops/sec [328,804..331,651] → 322,465 ops/sec [308,024..393,699] ~ overlap (-2.5%)
number coercion 9,446 ops/sec [8,411..11,007] → 15,327 ops/sec [14,953..15,767] 🟢 +62.3% 12,974 ops/sec [10,772..16,416] → 19,654 ops/sec [17,428..22,318] 🟢 +51.5%
toFixed 16,561 ops/sec [13,666..17,425] → 27,049 ops/sec [26,677..36,446] 🟢 +63.3% 17,728 ops/sec [15,345..23,288] → 29,826 ops/sec [28,671..31,593] 🟢 +68.2%
toString 22,850 ops/sec [21,786..28,452] → 41,645 ops/sec [40,969..46,613] 🟢 +82.3% 29,683 ops/sec [25,209..38,287] → 50,508 ops/sec [47,053..59,674] 🟢 +70.2%
toString non-integer (shortest round-trip) 5,646 ops/sec [5,152..6,640] → 8,781 ops/sec [8,539..9,648] 🟢 +55.5% 8,368 ops/sec [7,139..10,798] → 13,525 ops/sec [13,028..15,624] 🟢 +61.6%
valueOf 38,674 ops/sec [35,399..46,749] → 57,504 ops/sec [57,082..58,545] 🟢 +48.7% 39,190 ops/sec [34,431..45,909] → 64,480 ops/sec [62,584..84,792] 🟢 +64.5%
toPrecision 16,143 ops/sec [13,417..19,232] → 24,781 ops/sec [24,612..26,394] 🟢 +53.5% 14,334 ops/sec [12,832..18,111] → 26,792 ops/sec [26,296..27,198] 🟢 +86.9%
Number.isNaN 37,831 ops/sec [31,427..45,005] → 57,927 ops/sec [56,645..59,186] 🟢 +53.1% 38,191 ops/sec [37,063..45,261] → 69,854 ops/sec [69,094..72,715] 🟢 +82.9%
Number.isFinite 33,059 ops/sec [29,832..47,752] → 56,543 ops/sec [55,100..68,790] 🟢 +71.0% 36,276 ops/sec [32,922..41,502] → 65,989 ops/sec [65,175..73,206] 🟢 +81.9%
Number.isInteger 32,549 ops/sec [31,579..47,024] → 59,003 ops/sec [57,783..63,564] 🟢 +81.3% 40,595 ops/sec [30,048..48,836] → 70,590 ops/sec [63,976..73,250] 🟢 +73.9%
Number.parseInt and parseFloat 11,697 ops/sec [11,507..16,062] → 20,887 ops/sec [20,638..21,208] 🟢 +78.6% 14,899 ops/sec [12,831..18,570] → 22,648 ops/sec [21,579..23,048] 🟢 +52.0%
objects.js — Interp: 🟢 8 · avg +59.5% · Bytecode: 🟢 7, 🔴 1 · avg +54.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
create simple object 84,995 ops/sec [77,043..101,729] → 127,414 ops/sec [125,940..127,894] 🟢 +49.9% 98,921 ops/sec [82,232..127,691] → 133,584 ops/sec [131,946..142,336] 🟢 +35.0%
create nested object 47,727 ops/sec [37,593..56,822] → 70,312 ops/sec [69,314..83,910] 🟢 +47.3% 45,335 ops/sec [39,002..58,729] → 70,581 ops/sec [68,932..72,052] 🟢 +55.7%
create 50 objects via Array.from 1,386 ops/sec [1,276..1,433] → 2,431 ops/sec [2,409..2,563] 🟢 +75.4% 1,434 ops/sec [1,178..1,819] → 2,174 ops/sec [2,091..2,327] 🟢 +51.6%
property read 66,046 ops/sec [61,341..73,993] → 104,333 ops/sec [103,283..104,472] 🟢 +58.0% 389,723 ops/sec [348,486..405,107] → 301,991 ops/sec [289,674..344,569] 🔴 -22.5%
Object.keys 31,226 ops/sec [27,665..38,152] → 51,424 ops/sec [50,723..55,689] 🟢 +64.7% 34,078 ops/sec [29,398..39,033] → 62,264 ops/sec [59,225..64,198] 🟢 +82.7%
Object.keys over 2000 descending-inserted index keys 193 ops/sec [159..221] → 322 ops/sec [311..340] 🟢 +67.1% 208 ops/sec [181..297] → 410 ops/sec [322..576] 🟢 +97.2%
Object.entries 16,472 ops/sec [15,860..20,328] → 26,487 ops/sec [26,320..27,076] 🟢 +60.8% 19,855 ops/sec [19,511..19,895] → 33,163 ops/sec [31,875..34,332] 🟢 +67.0%
spread operator 24,216 ops/sec [22,050..29,148] → 37,053 ops/sec [36,755..37,173] 🟢 +53.0% 28,715 ops/sec [28,398..29,555] → 48,118 ops/sec [47,607..49,908] 🟢 +67.6%
promises.js — Interp: 🟢 12 · avg +71.6% · Bytecode: 🟢 11, 1 unch. · avg +54.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
Promise.resolve(value) 33,153 ops/sec [31,959..38,168] → 59,827 ops/sec [58,208..82,037] 🟢 +80.5% 34,612 ops/sec [31,537..36,620] → 58,792 ops/sec [56,239..63,700] 🟢 +69.9%
new Promise(resolve => resolve(value)) 26,008 ops/sec [25,326..26,190] → 42,160 ops/sec [40,549..43,664] 🟢 +62.1% 25,809 ops/sec [22,945..26,145] → 42,239 ops/sec [41,814..50,104] 🟢 +63.7%
Promise.reject(reason) 35,815 ops/sec [33,788..40,672] → 62,413 ops/sec [57,448..67,022] 🟢 +74.3% 33,742 ops/sec [26,949..44,337] → 58,309 ops/sec [57,761..64,210] 🟢 +72.8%
resolve + then (1 handler) 12,065 ops/sec [9,779..12,373] → 19,961 ops/sec [19,544..20,431] 🟢 +65.4% 11,846 ops/sec [10,124..14,297] → 19,934 ops/sec [19,607..20,181] 🟢 +68.3%
resolve + then chain (3 deep) 4,883 ops/sec [4,071..5,306] → 8,565 ops/sec [8,369..10,067] 🟢 +75.4% 5,297 ops/sec [4,579..6,468] → 8,297 ops/sec [8,171..9,376] 🟢 +56.6%
resolve + then chain (10 deep) 1,659 ops/sec [1,484..1,971] → 2,982 ops/sec [2,857..3,332] 🟢 +79.8% 2,146 ops/sec [2,050..2,171] → 2,843 ops/sec [2,731..3,861] 🟢 +32.5%
reject + catch + then 6,320 ops/sec [5,651..7,651] → 11,693 ops/sec [11,402..12,141] 🟢 +85.0% 7,697 ops/sec [6,294..9,148] → 11,944 ops/sec [11,709..12,883] 🟢 +55.2%
resolve + finally + then 2,879 ops/sec [2,701..3,927] → 5,631 ops/sec [5,424..5,848] 🟢 +95.6% 4,287 ops/sec [3,053..5,337] → 5,571 ops/sec [5,397..5,613] 🟢 +29.9%
Promise.all (5 resolved) 2,337 ops/sec [2,131..2,455] → 3,841 ops/sec [3,764..3,874] 🟢 +64.3% 2,940 ops/sec [2,547..3,587] → 3,619 ops/sec [3,467..3,705] ~ overlap (+23.1%)
Promise.race (5 resolved) 2,620 ops/sec [2,568..2,880] → 4,291 ops/sec [4,250..7,003] 🟢 +63.8% 2,809 ops/sec [2,309..3,356] → 4,235 ops/sec [4,161..4,754] 🟢 +50.8%
Promise.allSettled (5 mixed) 1,981 ops/sec [1,896..2,427] → 3,233 ops/sec [3,125..3,798] 🟢 +63.2% 1,845 ops/sec [1,750..2,625] → 3,101 ops/sec [3,042..3,452] 🟢 +68.1%
Promise.any (5 mixed) 2,585 ops/sec [2,305..2,806] → 3,860 ops/sec [3,780..4,085] 🟢 +49.3% 2,289 ops/sec [1,994..2,709] → 3,679 ops/sec [3,592..4,166] 🟢 +60.8%
property-access.js — Interp: 🟢 5 · avg +45.4% · Bytecode: 🟢 5 · avg +56.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
class instance fields across 1000 instances 79 ops/sec [78..80] → 105 ops/sec [104..106] 🟢 +32.7% 555 ops/sec [553..568] → 896 ops/sec [864..928] 🟢 +61.2%
object literal fields across 1000 literals 77 ops/sec [74..94] → 107 ops/sec [104..108] 🟢 +38.9% 557 ops/sec [421..679] → 883 ops/sec [871..912] 🟢 +58.7%
mixed-shape literals across 1000 literals 71 ops/sec [70..88] → 107 ops/sec [105..138] 🟢 +50.2% 417 ops/sec [350..536] → 630 ops/sec [618..714] 🟢 +50.9%
own-class method across 1000 instances 48 ops/sec [43..50] → 74 ops/sec [67..100] 🟢 +54.8% 275 ops/sec [243..351] → 442 ops/sec [440..443] 🟢 +60.6%
inherited method across 1000 instances 51 ops/sec [45..59] → 76 ops/sec [76..80] 🟢 +50.5% 284 ops/sec [240..367] → 426 ops/sec [425..427] 🟢 +50.1%
regexp.js — Interp: 🟢 13 · avg +64.4% · Bytecode: 🟢 12, 1 unch. · avg +55.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
regex literal creation 4,867 ops/sec [4,852..5,054] → 7,250 ops/sec [7,205..7,538] 🟢 +49.0% 128,802 ops/sec [107,962..156,838] → 201,006 ops/sec [200,295..201,415] 🟢 +56.1%
new RegExp(pattern, flags) 4,617 ops/sec [4,254..5,110] → 6,652 ops/sec [6,574..8,423] 🟢 +44.1% 4,836 ops/sec [4,306..5,730] → 6,481 ops/sec [6,444..6,505] 🟢 +34.0%
RegExp(existingRegex) returns the same regex 87,939 ops/sec [80,451..104,194] → 154,257 ops/sec [147,626..166,733] 🟢 +75.4% 232,366 ops/sec [230,024..235,148] → 199,573 ops/sec [188,117..237,580] ~ overlap (-14.1%)
test() on a global regex 33,401 ops/sec [28,910..39,106] → 60,577 ops/sec [59,630..89,947] 🟢 +81.4% 42,215 ops/sec [27,880..53,434] → 74,634 ops/sec [73,454..75,102] 🟢 +76.8%
exec() with capture groups 23,014 ops/sec [18,253..27,430] → 34,654 ops/sec [34,541..39,142] 🟢 +50.6% 23,155 ops/sec [19,985..28,564] → 38,180 ops/sec [37,723..39,824] 🟢 +64.9%
toString() 25,963 ops/sec [22,529..34,123] → 47,626 ops/sec [46,947..47,648] 🟢 +83.4% 29,791 ops/sec [23,396..32,865] → 53,049 ops/sec [52,562..57,849] 🟢 +78.1%
match() with global regex 12,088 ops/sec [10,386..13,032] → 21,667 ops/sec [20,817..23,389] 🟢 +79.2% 15,310 ops/sec [12,785..16,871] → 24,819 ops/sec [24,085..28,709] 🟢 +62.1%
match() with many global results 614 ops/sec [557..706] → 1,041 ops/sec [1,027..1,084] 🟢 +69.4% 634 ops/sec [553..780] → 1,074 ops/sec [1,058..1,159] 🟢 +69.4%
matchAll() with capture groups 4,363 ops/sec [3,896..4,419] → 7,398 ops/sec [7,369..7,402] 🟢 +69.6% 6,234 ops/sec [4,460..8,350] → 9,755 ops/sec [9,380..9,863] 🟢 +56.5%
replace() with global regex 11,852 ops/sec [11,773..12,240] → 20,829 ops/sec [20,665..21,239] 🟢 +75.7% 14,786 ops/sec [12,815..15,351] → 23,454 ops/sec [23,056..24,701] 🟢 +58.6%
replace() with many global results 530 ops/sec [452..714] → 786 ops/sec [785..827] 🟢 +48.4% 569 ops/sec [410..637] → 845 ops/sec [840..864] 🟢 +48.7%
search() with regex 26,307 ops/sec [21,776..34,646] → 38,234 ops/sec [37,842..38,665] 🟢 +45.3% 31,708 ops/sec [23,439..37,572] → 51,305 ops/sec [50,169..51,434] 🟢 +61.8%
split() with regex separator 6,362 ops/sec [5,102..7,178] → 10,515 ops/sec [9,325..10,617] 🟢 +65.3% 6,119 ops/sec [4,386..8,332] → 10,167 ops/sec [9,959..10,263] 🟢 +66.2%
strings.js — Interp: 🟢 19 · avg +37.7% · Bytecode: 🟢 16, 3 unch. · avg +38.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
string concatenation 32,821 ops/sec [29,095..32,964] → 61,507 ops/sec [60,676..62,818] 🟢 +87.4% 613,889 ops/sec [580,224..751,172] → 517,832 ops/sec [495,142..611,566] ~ overlap (-15.6%)
template literal 77,556 ops/sec [67,137..81,219] → 113,426 ops/sec [112,851..120,288] 🟢 +46.3% 558,824 ops/sec [523,749..676,264] → 474,028 ops/sec [449,943..546,274] ~ overlap (-15.2%)
string repeat 56,703 ops/sec [55,355..57,765] → 83,679 ops/sec [80,505..84,193] 🟢 +47.6% 59,865 ops/sec [52,482..71,040] → 107,648 ops/sec [106,110..112,287] 🟢 +79.8%
split and join 23,836 ops/sec [21,656..28,854] → 31,770 ops/sec [31,203..32,302] 🟢 +33.3% 27,982 ops/sec [24,249..41,195] → 52,438 ops/sec [47,497..57,140] 🟢 +87.4%
indexOf and includes 26,679 ops/sec [24,300..28,221] → 34,956 ops/sec [34,642..36,337] 🟢 +31.0% 31,498 ops/sec [30,405..37,362] → 52,107 ops/sec [50,140..62,722] 🟢 +65.4%
toUpperCase and toLowerCase 26,170 ops/sec [20,586..32,424] → 34,559 ops/sec [32,926..34,651] 🟢 +32.1% 29,463 ops/sec [26,353..34,401] → 43,221 ops/sec [42,871..44,263] 🟢 +46.7%
slice and substring 25,468 ops/sec [21,516..29,893] → 33,032 ops/sec [32,454..33,322] 🟢 +29.7% 31,155 ops/sec [25,268..32,296] → 47,964 ops/sec [47,254..49,785] 🟢 +54.0%
trim operations 24,957 ops/sec [23,884..28,790] → 36,085 ops/sec [35,943..38,625] 🟢 +44.6% 35,875 ops/sec [31,915..37,977] → 53,930 ops/sec [52,028..64,001] 🟢 +50.3%
replace and replaceAll 26,976 ops/sec [22,212..36,026] → 39,880 ops/sec [39,738..40,032] 🟢 +47.8% 34,498 ops/sec [32,602..35,184] → 61,435 ops/sec [61,070..61,646] 🟢 +78.1%
startsWith and endsWith 20,175 ops/sec [17,745..21,896] → 28,049 ops/sec [27,582..28,089] 🟢 +39.0% 31,350 ops/sec [20,363..33,029] → 41,574 ops/sec [41,389..41,654] 🟢 +32.6%
padStart and padEnd 23,509 ops/sec [21,990..32,887] → 40,739 ops/sec [40,249..41,737] 🟢 +73.3% 45,526 ops/sec [42,800..52,513] → 64,114 ops/sec [63,410..64,950] 🟢 +40.8%
identity tag, no substitutions 73,152 ops/sec [60,897..81,581] → 93,495 ops/sec [93,253..96,132] 🟢 +27.8% 170,555 ops/sec [158,270..183,200] → 155,662 ops/sec [153,455..165,979] ~ overlap (-8.7%)
tag with 1 substitution 15,673 ops/sec [14,786..17,194] → 19,921 ops/sec [19,453..22,801] 🟢 +27.1% 18,147 ops/sec [16,113..19,502] → 29,200 ops/sec [29,041..29,425] 🟢 +60.9%
tag with 3 substitutions 9,810 ops/sec [8,998..10,503] → 11,304 ops/sec [11,242..11,395] 🟢 +15.2% 12,360 ops/sec [11,490..12,993] → 17,100 ops/sec [16,740..17,332] 🟢 +38.3%
tag with 6 substitutions 5,256 ops/sec [4,792..5,872] → 6,800 ops/sec [6,616..6,859] 🟢 +29.4% 7,617 ops/sec [7,240..8,395] → 10,716 ops/sec [10,333..10,749] 🟢 +40.7%
String.raw, no substitutions 73,051 ops/sec [57,021..75,533] → 82,325 ops/sec [81,815..92,155] 🟢 +12.7% 68,910 ops/sec [63,148..79,643] → 83,221 ops/sec [82,887..83,357] 🟢 +20.8%
String.raw, 2 substitutions 45,984 ops/sec [41,386..49,752] → 56,690 ops/sec [55,830..61,649] 🟢 +23.3% 67,666 ops/sec [61,614..72,362] → 75,050 ops/sec [72,465..78,292] 🟢 +10.9%
tag accessing .raw array 25,052 ops/sec [23,777..27,603] → 33,589 ops/sec [32,999..36,750] 🟢 +34.1% 34,160 ops/sec [30,763..40,983] → 45,925 ops/sec [45,500..46,318] 🟢 +34.4%
method as tag (this binding) 10,345 ops/sec [8,887..10,752] → 13,941 ops/sec [13,895..14,535] 🟢 +34.8% 17,964 ops/sec [16,907..19,446] → 22,761 ops/sec [22,580..23,157] 🟢 +26.7%
temporal.js — Interp: 🟢 6 · avg +49.0% · Bytecode: 🟢 6 · avg +57.4%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
PlainDate.add({ months: 1 }) 26,503 ops/sec [23,282..33,495] → 39,416 ops/sec [38,470..40,854] 🟢 +48.7% 25,290 ops/sec [22,667..32,688] → 40,915 ops/sec [40,217..48,628] 🟢 +61.8%
PlainDate.until(..., { largestUnit: 'months' }) 28,763 ops/sec [24,909..34,134] → 45,356 ops/sec [44,079..47,476] 🟢 +57.7% 33,147 ops/sec [30,277..38,495] → 50,583 ops/sec [49,363..51,451] 🟢 +52.6%
Duration.total days relative to PlainDate 23,563 ops/sec [20,626..27,517] → 36,146 ops/sec [35,536..37,644] 🟢 +53.4% 25,783 ops/sec [17,912..33,825] → 40,300 ops/sec [39,745..40,689] 🟢 +56.3%
Duration.round to hours 21,167 ops/sec [17,726..24,620] → 30,732 ops/sec [30,288..31,316] 🟢 +45.2% 21,240 ops/sec [19,309..27,933] → 32,337 ops/sec [31,580..32,725] 🟢 +52.2%
ZonedDateTime.from named time zone 5,591 ops/sec [4,888..6,373] → 8,431 ops/sec [7,816..12,460] 🟢 +50.8% 5,995 ops/sec [5,105..8,465] → 10,385 ops/sec [8,838..10,737] 🟢 +73.2%
ZonedDateTime.since across DST 6,702 ops/sec [5,836..7,657] → 9,268 ops/sec [9,149..9,714] 🟢 +38.3% 6,779 ops/sec [5,494..7,177] → 10,065 ops/sec [9,920..10,210] 🟢 +48.5%
tsv.js — Interp: 🟢 9 · avg +60.8% · Bytecode: 🟢 9 · avg +40.8%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
parse simple 3-column TSV 20,929 ops/sec [19,488..23,875] → 35,115 ops/sec [34,997..35,570] 🟢 +67.8% 25,382 ops/sec [21,326..29,771] → 37,113 ops/sec [34,349..38,571] 🟢 +46.2%
parse 10-row TSV 5,329 ops/sec [5,283..5,520] → 9,515 ops/sec [9,455..9,663] 🟢 +78.6% 7,142 ops/sec [6,368..8,012] → 9,857 ops/sec [9,716..10,031] 🟢 +38.0%
parse 100-row TSV 817 ops/sec [763..862] → 1,613 ops/sec [1,590..2,219] 🟢 +97.4% 1,188 ops/sec [999..1,349] → 1,584 ops/sec [1,554..1,758] 🟢 +33.3%
parse TSV with backslash-escaped fields 5,171 ops/sec [4,673..5,737] → 8,339 ops/sec [8,271..8,611] 🟢 +61.3% 6,523 ops/sec [5,652..6,851] → 9,167 ops/sec [8,842..9,469] 🟢 +40.5%
parse without headers (array of arrays) 2,106 ops/sec [1,873..2,418] → 4,600 ops/sec [4,410..5,103] 🟢 +118.4% 2,847 ops/sec [2,211..3,073] → 4,659 ops/sec [4,623..4,684] 🟢 +63.6%
stringify array of objects 8,558 ops/sec [6,852..9,253] → 11,115 ops/sec [10,715..11,131] 🟢 +29.9% 9,295 ops/sec [7,514..11,366] → 12,357 ops/sec [12,271..12,436] 🟢 +32.9%
stringify array of arrays 2,146 ops/sec [1,782..2,487] → 2,759 ops/sec [2,750..3,319] 🟢 +28.5% 2,216 ops/sec [2,115..2,568] → 3,081 ops/sec [3,038..3,103] 🟢 +39.1%
stringify with values needing escaping 7,152 ops/sec [6,611..7,695] → 8,881 ops/sec [8,783..8,941] 🟢 +24.2% 8,445 ops/sec [7,468..8,764] → 10,138 ops/sec [10,019..10,157] 🟢 +20.1%
parse then stringify 2,388 ops/sec [2,094..2,714] → 3,379 ops/sec [3,343..3,422] 🟢 +41.5% 2,404 ops/sec [2,318..2,590] → 3,686 ops/sec [3,574..3,773] 🟢 +53.4%
typed-arrays.js — Interp: 🟢 14, 🔴 5, 3 unch. · avg +22.2% · Bytecode: 🟢 18, 4 unch. · avg +39.9%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
new Int32Array(0) 61,745 ops/sec [53,090..62,212] → 86,647 ops/sec [84,799..87,035] 🟢 +40.3% 65,511 ops/sec [55,411..82,790] → 106,879 ops/sec [106,461..107,351] 🟢 +63.1%
new Int32Array(100) 52,275 ops/sec [49,533..52,629] → 83,829 ops/sec [80,734..107,225] 🟢 +60.4% 80,153 ops/sec [71,381..89,394] → 101,189 ops/sec [99,577..101,749] 🟢 +26.2%
new Int32Array(1000) 48,989 ops/sec [47,057..49,870] → 78,522 ops/sec [70,582..83,392] 🟢 +60.3% 63,970 ops/sec [60,492..70,534] → 78,106 ops/sec [77,481..78,893] 🟢 +22.1%
new Float64Array(100) 52,064 ops/sec [41,368..66,564] → 83,057 ops/sec [81,857..83,555] 🟢 +59.5% 91,781 ops/sec [83,567..94,029] → 95,855 ops/sec [94,090..97,531] 🟢 +4.4%
Int32Array.from([...]) 993 ops/sec [654..1,062] → 1,267 ops/sec [1,248..1,323] 🟢 +27.6% 925 ops/sec [810..1,019] → 1,200 ops/sec [1,185..1,346] 🟢 +29.8%
Int32Array.of(1, 2, 3, 4, 5) 44,791 ops/sec [43,688..46,025] → 61,090 ops/sec [60,372..69,063] 🟢 +36.4% 49,486 ops/sec [44,535..50,148] → 65,513 ops/sec [65,032..66,254] 🟢 +32.4%
sequential write 100 elements 818 ops/sec [762..872] → 989 ops/sec [979..1,046] 🟢 +20.8% 5,441 ops/sec [5,337..5,559] → 7,661 ops/sec [7,618..7,712] 🟢 +40.8%
sequential read 100 elements 831 ops/sec [741..916] → 1,023 ops/sec [1,012..1,048] 🟢 +23.0% 7,662 ops/sec [5,682..8,401] → 9,088 ops/sec [8,573..15,199] 🟢 +18.6%
Float64Array write 100 elements 651 ops/sec [507..715] → 867 ops/sec [858..895] 🟢 +33.3% 5,518 ops/sec [4,863..5,921] → 10,578 ops/sec [10,535..10,581] 🟢 +91.7%
fill(42) 4,950 ops/sec [4,386..5,769] → 5,721 ops/sec [5,629..5,989] ~ overlap (+15.6%) 5,639 ops/sec [4,828..5,832] → 11,903 ops/sec [11,867..11,925] 🟢 +111.1%
slice() 36,671 ops/sec [33,201..38,271] → 46,110 ops/sec [45,974..46,300] 🟢 +25.7% 40,639 ops/sec [33,320..42,259] → 77,620 ops/sec [77,000..78,004] 🟢 +91.0%
map(x => x * 2) 1,279 ops/sec [1,197..1,363] → 3,224 ops/sec [3,198..3,255] 🟢 +152.1% 1,521 ops/sec [1,415..1,632] → 3,284 ops/sec [3,263..3,300] 🟢 +116.0%
filter(x => x > 50) 1,249 ops/sec [1,132..1,360] → 2,159 ops/sec [1,871..3,312] 🟢 +72.8% 2,955 ops/sec [2,887..2,961] → 3,451 ops/sec [3,439..3,467] 🟢 +16.8%
reduce (sum) 2,621 ops/sec [2,247..2,742] → 1,967 ops/sec [1,878..2,012] 🔴 -25.0% 1,250 ops/sec [1,191..3,037] → 3,238 ops/sec [3,165..3,267] 🟢 +159.0%
sort() 33,455 ops/sec [27,666..36,569] → 20,649 ops/sec [18,725..21,448] 🔴 -38.3% 32,553 ops/sec [31,142..35,852] → 37,406 ops/sec [37,384..37,522] 🟢 +14.9%
indexOf() 33,224 ops/sec [30,635..35,936] → 23,685 ops/sec [23,590..23,824] 🔴 -28.7% 42,530 ops/sec [33,997..43,201] → 45,177 ops/sec [44,912..45,608] 🟢 +6.2%
reverse() 40,732 ops/sec [21,626..48,112] → 26,512 ops/sec [26,280..26,614] ~ overlap (-34.9%) 51,638 ops/sec [45,757..53,368] → 53,266 ops/sec [53,037..53,588] ~ overlap (+3.2%)
create view over existing buffer 159,344 ops/sec [143,054..172,939] → 101,627 ops/sec [101,215..102,101] 🔴 -36.2% 202,709 ops/sec [198,922..209,401] → 217,341 ops/sec [216,469..219,939] 🟢 +7.2%
subarray() 68,540 ops/sec [61,374..74,069] → 52,704 ops/sec [51,240..57,420] 🔴 -23.1% 82,207 ops/sec [21,216..83,121] → 89,274 ops/sec [88,964..89,711] 🟢 +8.6%
set() from array 89,828 ops/sec [89,511..90,135] → 96,006 ops/sec [60,129..108,361] ~ overlap (+6.9%) 99,751 ops/sec [88,304..117,247] → 116,475 ops/sec [116,258..116,711] ~ overlap (+16.8%)
for-of loop 2,093 ops/sec [2,083..2,103] → 2,338 ops/sec [2,330..2,346] 🟢 +11.7% 18,092 ops/sec [12,926..18,295] → 18,252 ops/sec [18,167..18,273] ~ overlap (+0.9%)
spread into array 7,761 ops/sec [7,731..7,784] → 9,921 ops/sec [9,901..9,940] 🟢 +27.8% 31,055 ops/sec [30,742..31,321] → 30,180 ops/sec [29,948..30,797] ~ overlap (-2.8%)
uint8array-encoding.js — Interp: 🟢 18 · avg +86.0% · Bytecode: 🟢 14, 🔴 2, 2 unch. · avg +29.3%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
short (5 bytes) 67,409 ops/sec [56,488..77,236] → 115,678 ops/sec [114,749..117,907] 🟢 +71.6% 95,176 ops/sec [81,937..103,260] → 127,754 ops/sec [126,784..128,893] 🟢 +34.2%
medium (450 bytes) 45,822 ops/sec [41,159..49,711] → 78,365 ops/sec [77,132..79,304] 🟢 +71.0% 64,758 ops/sec [55,303..78,029] → 85,535 ops/sec [84,176..86,088] 🟢 +32.1%
large (4096 bytes) 15,494 ops/sec [13,564..17,037] → 20,532 ops/sec [20,268..20,969] 🟢 +32.5% 19,425 ops/sec [14,665..19,654] → 22,730 ops/sec [22,417..24,761] 🟢 +17.0%
base64url alphabet 34,331 ops/sec [32,162..44,057] → 58,151 ops/sec [58,092..58,245] 🟢 +69.4% 43,356 ops/sec [35,462..58,965] → 63,101 ops/sec [62,729..66,142] 🟢 +45.5%
omitPadding 61,462 ops/sec [39,995..72,941] → 86,529 ops/sec [82,309..98,911] 🟢 +40.8% 63,321 ops/sec [55,049..69,995] → 84,720 ops/sec [84,314..85,020] 🟢 +33.8%
short (8 chars) 76,298 ops/sec [66,099..81,251] → 94,183 ops/sec [93,216..115,848] 🟢 +23.4% 76,499 ops/sec [73,336..83,332] → 99,075 ops/sec [97,744..99,538] 🟢 +29.5%
medium (600 chars) 14,673 ops/sec [13,504..14,922] → 18,498 ops/sec [17,792..18,943] 🟢 +26.1% 15,267 ops/sec [13,870..17,395] → 18,288 ops/sec [18,149..18,657] 🟢 +19.8%
large (5464 chars) 1,925 ops/sec [1,640..2,001] → 2,424 ops/sec [2,391..2,644] 🟢 +26.0% 2,171 ops/sec [1,974..2,248] → 2,433 ops/sec [2,412..2,448] 🟢 +12.1%
short (5 bytes) 88,921 ops/sec [71,531..110,488] → 123,740 ops/sec [121,005..124,294] 🟢 +39.2% 111,025 ops/sec [108,300..114,651] → 135,527 ops/sec [133,434..137,142] 🟢 +22.1%
medium (450 bytes) 59,693 ops/sec [51,263..68,013] → 118,739 ops/sec [68,779..122,937] 🟢 +98.9% 58,703 ops/sec [56,057..60,688] → 80,421 ops/sec [79,893..81,109] 🟢 +37.0%
large (4096 bytes) 13,193 ops/sec [12,504..14,806] → 22,622 ops/sec [16,310..31,946] 🟢 +71.5% 14,101 ops/sec [13,724..14,776] → 17,905 ops/sec [17,118..18,021] 🟢 +27.0%
short (10 chars) 74,187 ops/sec [61,110..86,584] → 175,497 ops/sec [174,687..176,276] 🟢 +136.6% 49,208 ops/sec [43,312..103,991] → 110,546 ops/sec [109,699..110,749] 🟢 +124.7%
medium (900 chars) 59,762 ops/sec [51,701..62,532] → 128,729 ops/sec [81,825..129,582] 🟢 +115.4% 75,620 ops/sec [69,524..77,844] → 82,307 ops/sec [81,948..82,805] 🟢 +8.8%
large (8192 chars) 23,291 ops/sec [18,853..25,270] → 28,619 ops/sec [27,893..28,868] 🟢 +22.9% 19,845 ops/sec [18,245..23,717] → 27,158 ops/sec [25,958..29,594] 🟢 +36.9%
setFromBase64 (450 bytes) 14,747 ops/sec [13,230..16,519] → 32,477 ops/sec [32,142..32,596] 🟢 +120.2% 14,996 ops/sec [14,666..17,114] → 17,078 ops/sec [16,989..17,105] ~ overlap (+13.9%)
setFromHex (450 bytes) 14,267 ops/sec [11,536..14,567] → 31,870 ops/sec [31,689..32,017] 🟢 +123.4% 10,379 ops/sec [5,880..20,370] → 20,274 ops/sec [20,186..20,346] ~ overlap (+95.3%)
toBase64 → fromBase64 (450 bytes) 6,484 ops/sec [6,046..14,961] → 29,371 ops/sec [29,284..29,391] 🟢 +353.0% 23,077 ops/sec [20,151..26,268] → 15,909 ops/sec [15,748..15,972] 🔴 -31.1%
toHex → fromHex (450 bytes) 33,594 ops/sec [32,415..35,680] → 69,349 ops/sec [68,991..69,508] 🟢 +106.4% 66,733 ops/sec [59,949..70,724] → 45,544 ops/sec [45,188..45,729] 🔴 -31.8%
weak-collections.js — Interp: 🟢 10, 🔴 2, 3 unch. · avg +20.1% · Bytecode: 🟢 12, 🔴 1, 2 unch. · avg +29.5%
Benchmark Interpreted (main → PR) Δ Bytecode (main → PR) Δ
constructor from 50 entries 6,071 ops/sec [5,338..6,979] → 7,450 ops/sec [7,344..7,554] 🟢 +22.7% 5,653 ops/sec [4,418..6,711] → 7,672 ops/sec [7,508..8,175] 🟢 +35.7%
set 50 object keys 1,913 ops/sec [1,794..2,178] → 2,564 ops/sec [2,526..2,603] 🟢 +34.0% 1,969 ops/sec [1,750..2,302] → 2,862 ops/sec [2,798..3,005] 🟢 +45.3%
get lookups (50 entries) 23,349 ops/sec [20,737..24,844] → 33,511 ops/sec [33,169..34,117] 🟢 +43.5% 42,860 ops/sec [33,577..53,495] → 60,485 ops/sec [59,836..61,257] 🟢 +41.1%
has checks (50 entries) 30,585 ops/sec [25,956..33,630] → 47,497 ops/sec [44,971..47,713] 🟢 +55.3% 62,212 ops/sec [59,408..69,028] → 74,108 ops/sec [73,635..78,556] 🟢 +19.1%
delete entries 1,666 ops/sec [1,393..1,804] → 2,495 ops/sec [2,481..2,500] 🟢 +49.8% 2,470 ops/sec [2,282..2,763] → 2,706 ops/sec [2,683..2,726] ~ overlap (+9.5%)
non-registered symbol keys 5,156 ops/sec [4,801..5,347] → 5,697 ops/sec [5,670..5,718] 🟢 +10.5% 5,214 ops/sec [4,742..5,474] → 6,584 ops/sec [6,458..6,695] 🟢 +26.3%
getOrInsert 1,740 ops/sec [1,666..1,979] → 2,318 ops/sec [2,309..2,327] 🟢 +33.2% 2,103 ops/sec [1,930..2,191] → 2,664 ops/sec [2,652..2,686] 🟢 +26.7%
getOrInsertComputed 1,239 ops/sec [1,148..1,347] → 2,286 ops/sec [1,379..2,312] 🟢 +84.5% 1,260 ops/sec [1,125..1,420] → 1,475 ops/sec [1,471..1,516] 🟢 +17.1%
forced gc live-key retention 1,195 ops/sec [1,080..1,245] → 798 ops/sec [785..914] 🔴 -33.2% 1,074 ops/sec [948..1,166] → 850 ops/sec [795..896] 🔴 -20.9%
constructor from 50 values 6,899 ops/sec [6,436..7,009] → 9,198 ops/sec [8,487..16,126] 🟢 +33.3% 7,612 ops/sec [6,550..8,668] → 9,300 ops/sec [9,240..9,494] 🟢 +22.2%
add 50 object values 3,326 ops/sec [2,154..4,109] → 4,622 ops/sec [4,587..4,664] 🟢 +38.9% 2,639 ops/sec [2,341..2,990] → 3,083 ops/sec [3,077..3,085] 🟢 +16.8%
has checks (50 values) 65,964 ops/sec [65,747..66,127] → 46,410 ops/sec [46,029..77,841] ~ overlap (-29.6%) 59,968 ops/sec [53,500..60,887] → 74,491 ops/sec [74,010..75,960] 🟢 +24.2%
delete values 8,897 ops/sec [8,847..8,951] → 6,981 ops/sec [6,916..6,992] 🔴 -21.5% 7,759 ops/sec [6,818..7,864] → 13,375 ops/sec [13,181..13,504] 🟢 +72.4%
non-registered symbol values 6,392 ops/sec [6,361..6,424] → 6,149 ops/sec [5,867..10,279] ~ overlap (-3.8%) 5,986 ops/sec [5,864..6,153] → 11,626 ops/sec [11,526..11,691] 🟢 +94.2%
forced gc pruning smoke 1,734 ops/sec [1,726..1,745] → 1,451 ops/sec [817..1,795] ~ overlap (-16.3%) 1,483 ops/sec [1,075..1,554] → 1,681 ops/sec [1,554..1,694] ~ overlap (+13.4%)

Deterministic profile diff

Deterministic profile diff: no significant changes.

Measured on ubuntu-latest x64. Each PR run also builds the main base and benchmarks it back-to-back on the same runner after a warm-up discard, so the ranges compare two runs measured under the same conditions; overlapping min/max ranges are treated as unchanged noise. Percentage deltas are secondary context. See docs/adr/0076.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

JetStream 3 Performance Barometer

Workload Status Goccia main Goccia PR QuickJS Node.js vs QuickJS vs Node.js
hash-map pass 0.55 0.55 13.64 346.98 24.76× 629.90×
ai-astar pass 1.88 1.89 56.45 407.16 29.84× 215.24×
gaussian-blur pass 0.35 0.34 7.92 311.93 22.99× 905.39×
raytrace-public-class-fields pass 0.39 0.38 10.90 200.17 28.35× 520.62×
sync-fs pass 0.82 0.84 26.44 209.75 31.48× 249.81×
lazy-collections pass 2.22 2.21 82.23 161.69 37.17× 73.09×

Geomean reference ratio: QuickJS 28.74×; Node.js 324.46×.

1.00× means aligned; values above 1.00× mean Goccia was proportionally slower after normalizing JetStream’s higher-is-better score. This is a directional barometer across runtimes with different goals, not a product ranking. Raw samples and failure details remain in the jetstream-report artifact.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

test262 Conformance

12 timeout(s) — counted separately from ordinary conformance failures; inspect the full artifact for affected tests.

Category Run Passed Δ Pass Failed Timeouts Δ Timeout Wrap-Infra Pass-rate Δ Rate
built-ins 23,812 23,719 +2 93 0 -2 0 99.6% ±0pp
harness 116 116 ±0 0 0 ±0 0 100.0% ±0pp
intl402 3,357 3,344 ±0 12 1 ±0 0 99.6% ±0pp
language 23,724 23,717 ±0 7 0 ±0 0 100.0% ±0pp
staging 1,483 1,387 +1 85 11 -1 0 93.5% +0.1pp
total 52,492 52,283 +3 197 12 -3 0 99.6% ±0pp

Areas closest to 100%

Area Pass rate Δ vs main Passing
language/expressions 100.0% ±0pp 11,101 / 11,102
intl402/Temporal 100.0% ±0pp 2,028 / 2,029
language/statements 99.9% ±0pp 9,341 / 9,347
Per-test deltas (+0 / -0 / timeout +0 / -3)

Resolved timeouts (3):

  • built-ins/decodeURI/S15.1.3.1_A2.5_T1.js
  • built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js
  • staging/sm/extensions/recursion.js

Steady-state failures and timeouts are non-blocking; PASS → non-timeout failure transitions fail the conformance gate. Measured on ubuntu-latest x64, bytecode mode. Areas grouped by the first two test262 path components; minimum 25 attempted tests, areas already at 100% excluded. Δ vs main compares against the most recent cached main baseline.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

AWFY Results

Target Status Goccia main Goccia PR QuickJS 2026-06-04 NodeJS v26.7.0 Δ PR vs main
Bounce pass 16.54ms 16.47ms 0.75ms 0.81ms ~ overlap (+0.46%)
CD pass 156.09ms 157.77ms 7.89ms 7.90ms ~ overlap (-1.07%)
DeltaBlue pass 3.56ms 3.60ms 219.39µs 1.22ms ~ overlap (-1.02%)
Havlak pass 62.45s 63.09s 3006.14ms 152.67ms 🔴 -1.02%
Json pass 277.20ms 280.10ms 10.17ms 3.46ms ~ overlap (-1.05%)
List pass 11.04ms 11.33ms 0.78ms 0.56ms 🔴 -2.65%
Mandelbrot pass 20.54µs 20.73µs 4.06µs 72.85µs ~ overlap (-0.90%)
NBody pass 287.09µs 281.49µs 20.90µs 278.33µs ~ overlap (+1.95%)
Permute pass 31.98ms 32.36ms 1.32ms 0.56ms 🔴 -1.19%
Queens pass 16.62ms 16.96ms 0.87ms 0.93ms 🔴 -2.02%
Richards pass 684.00ms 693.10ms 40.33ms 5.01ms 🔴 -1.33%
Sieve pass 9.97ms 10.17ms 394.21µs 0.54ms ~ overlap (-2.06%)
Storage pass 28.72ms 28.89ms 1.84ms 0.82ms ~ overlap (-0.57%)
Towers pass 46.12ms 46.34ms 2.20ms 0.88ms 🔴 -0.48%

Geomean Ratios

Ratio (row / column) Goccia main Goccia PR QuickJS 2026-06-04 NodeJS v26.7.0
Goccia main 1.000 0.991 17.514 19.347
Goccia PR 1.009 1.000 17.675 19.524
QuickJS 2026-06-04 0.057 0.057 1.000 1.105
NodeJS v26.7.0 0.052 0.051 0.905 1.000

14 pinned AWFY benchmarks. Medians from 5 interleaved samples per engine; raw JSON includes min/max/CV and is attached as the awfy-report artifact. Δ compares PR Goccia median against the same-runner main Goccia median; overlapping min/max ranges are treated as unchanged noise. Rows below 0.5ms are timer-floor sensitive.

…rallel win

Fresh-context multi-angle review of the first commit surfaced two real
regressions and one design improvement, all applied:

- Grant an already-fitting request in TryCollectForLimitedBytes: a
  cross-thread release landing after a caller's failed fit test could make
  the request fit, which the force predicate read as 'nothing to force' and
  callers took for a refusal — a spurious guest-visible RangeError (or a
  TGocciaMemoryLimitError from RequireNativeBytes) with headroom available.
  The old single-lock design made that interleaving unreachable; the split
  makes the explicit grant necessary. Pinned by a single-threaded contract
  test (grant-without-walking).
- Settle swept bytes in a finally: a destructor exception escaping mid-sweep
  would have stranded the already-recycled objects' bytes and permanently
  inflated FBytesAllocated (the old per-object Dec kept completed frees
  accounted on that path).
- Make the accounting lock per-collector instead of process-global: the
  global variant's shutdown-safety rationale was vacuous — a lock that
  outlives the collector cannot protect the freed fields anyway, so the
  per-collector field is safe on exactly the lifecycle-invariant terms the
  field accesses already require — and it put every worker's per-allocation
  counter update on one shared cache line. Contention workload at --jobs=8:
  22.3s -> 10.2s median (-54%, vs -19% for the global leaf lock);
  single-thread unchanged.
- Consolidate both reserve attempts onto one atomic fit-test-and-charge
  helper (TryChargeExternalBytesLocked), closing the latent overshoot where
  a re-entrant same-thread charge during the forced collection could have
  pushed the committed total past the ceiling, and deduplicating the fit
  predicate (FitsWithinLimitLocked).
- Size the cross-thread test's releaser (200k chunks) to span the owner-side
  churn so the exact-balance assertion keeps overlapping the race on faster
  machines; mutation re-checked 5/5 against the per-collector lock.
@frostney
frostney marked this pull request as ready for review August 24, 2026 11:10
@frostney
frostney merged commit f426b1b into main Aug 25, 2026
126 checks passed
@frostney
frostney deleted the claude/sad-napier-a84f51 branch August 25, 2026 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant